home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
vpbgib2.zip
/
GRAPH.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-11-02
|
35KB
|
1,249 lines
{█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█}
{█ █}
{█ Virtual Pascal Run-time Library v1.1 █}
{█ BGI Graphics unit for mixed BGI/Textmode █}
{█ ─────────────────────────────────────────────────█}
{█ Copyright (C) 1996 fPrint UK Ltd █}
{█ Written May-Sep 1996 by Allan Mertner █}
{█ Inspired by DIVERace by Michael Mrosowski █}
{█ Pipe interface engineered by Alex Vermeulen █}
{█ █}
{▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
Unit Graph;
Interface
{$Delphi+}
Uses
Use32, SysUtils;
type
Str12 = String[12];
EGraph = class(Exception);
Const
grOk = 0; // error status values reported by graphresult }
grNoInitGraph = -1; // BGI graphics not installed
grNotDetected = -2; // Graphics hardware not detected
grFileNotFound = -3; // Device driver file not found
grInvalidDriver = -4; // Invalid device driver file
grNoLoadMem = -5; // Not enough memory to load driver
grNoScanMem = -6; // Out of memory in scan fill
grNoFloodMem = -7; // Out of memory in flood fill
grFontNotFound = -8; // Font file not found
grNoFontMem = -9; // Not enough memory to load font
grInvalidMode = -10; // Invalid graphics mode for selected driver
grError = -11; // Graphics error (generic error)
grIOerror = -12; // Graphics I/O error
grInvalidFont = -13; // Invalid font file
grInvalidFontNum = -14; // Invalid font number
Detect = 0;
Black = 0; // Colour values
Blue = 1;
Green = 2;
Cyan = 3;
Red = 4;
Magenta = 5;
Brown = 6;
LightGray = 7;
DarkGray = 8;
LightBlue = 9;
LightGreen = 10;
LightCyan = 11;
LightRed = 12;
LightMagenta = 13;
Yellow = 14;
White = 15;
EGA_Black = 0; // different than DOS BGI values
EGA_Blue = 1;
EGA_Green = 2;
EGA_Cyan = 3;
EGA_Red = 4;
EGA_Magenta = 5;
EGA_Brown = 6;
EGA_LightGray = 7;
EGA_DarkGray = 8;
EGA_LightBlue = 9;
EGA_LightGreen = 10;
EGA_LightCyan = 11;
EGA_LightRed = 12;
EGA_LightMagenta = 13;
EGA_Yello = 14;
EGA_White = 15;
NormWidth = 1; // constants for line thickness
ThickWidth = 3;
SolidLn = 0; // constants for line patterns
DottedLn = 1;
CenterLn = 2;
DashedLn = 3;
UserBitLn = 4;
DefaultFont = 0; // font constants for settextstyle
TriplexFont = 1;
SmallFont = 2;
SansSerifFont = 3;
GothicFont = 4;
ScriptFont = 5;
SimplexFont = 6;
TriplexScrFont = 7;
ComplexFont = 8;
EuropeanFont = 9;
BoldFont = 10;
FontNames : Array[1..10] of Str12
= ( 'TRIP.CHR', 'LITT.CHR', 'SANS.CHR', 'GOTH.CHR', 'SCRI.CHR',
'SIMP.CHR', 'TSCR.CHR', 'LCOM.CHR', 'EURO.CHR', 'BOLD.CHR' );
HorizDir = 0;
VertDir = 90;
UserCharSize = 0;
ClipOn = TRUE;
ClipOff = FALSE;
TopOn = TRUE;
TopOff = FALSE;
EmptyFill = 0; // fill patterns
SolidFill = 1;
LineFill = 2;
LtSlashFill = 3;
SlashFill = 4;
BkSlashFill = 5;
LtBkSlashFill = 6;
HatchFill = 7;
XHatchFill = 8;
InterleaveFill = 9;
WideDotFill = 10;
CloseDotFill = 11;
UserFill = 12;
NormalPut = 0; // operators for image blits and setwritemode
CopyPut = 0;
XORPut = 1;
OrPut = 2;
AndPut = 3;
NotPut = 4;
LeftText = 0; // text justification constants
CenterText = 1;
RightText = 2;
BottomText = 0;
TopText = 2;
MaxColors = 255; // Different from DOS
LinePatterns : Array[0..3] of Word
= ( $FFFFFFFF, $33333333, $3CCF3CCF, $0F0F0F0F );
type
str4 = String[4];
FillPatternType = array [1..8] of Byte;
NewPatternType = array [0..15] of SmallWord;
IntArray = array [0..65000] of Integer;
PaletteType = record
Size : word;
Colors : array [0..MaxColors] of Byte;
end;
LineSettingsType = record
LineStyle : Word;
Pattern : Word;
Thickness : Word;
end;
TextSettingsType = record
Font : Word;
Direction : Word;
CharSize : Integer; { different than DOS BGI }
Horiz : Word;
Vert : Word;
userxscale: double;
useryscale: double;
end;
FillSettingsType = record
Pattern : Word;
Color : Word;
end;
PointType = record
X : Integer;
Y : Integer;
end;
PointArray = Array[0..65000] of PointType;
ViewPortType = record
X1 : Integer;
Y1 : Integer;
X2 : Integer;
Y2 : Integer;
Clip : Boolean;
end;
ArcCoordsType = record
X : Integer;
Y : Integer;
Xstart : Integer;
Ystart : Integer;
Xend : Integer;
Yend : Integer;
end;
MouseEventT =
( mb1Click, mb1DblClick, mb1BeginDrag, mb1EndDrag, mb1Down, mb1Up,
mb2Click, mb2DblClick, mb2BeginDrag, mb2EndDrag, mb2Down, mb2Up );
MouseEventRecT = record
Event : MouseEventT;
X,Y : Word;
end;
{ BGI Function Prototypes }
Procedure Arc(X, Y: Integer; StAngle, EndAngle, Radius: Word);
Procedure Bar(X1, Y1, X2, Y2: Integer);
Procedure Bar3D(X1, Y1, X2, Y2: Integer; Depth: Word; Top: Boolean);
Procedure Circle(X, Y: Integer; Radius: Word);
Procedure ClearDevice;
Procedure ClearViewport;
Procedure CloseGraph;
procedure DetectGraph(var GraphDriver, GraphMode: Integer);
Procedure DrawPoly(NumPoints: Word; var PolyPoints);
Procedure Ellipse(X, Y: Integer; StAngle, EndAngle: Word; XRadius, YRadius: Word);
Procedure FillEllipse(X, Y: Integer; XRadius, YRadius: Word);
Procedure FillPoly(NumPoints: Word; var PolyPoints);
Procedure FloodFill(X, Y: Integer; Border: Word);
Procedure GetArcCoords(var ArcCoords: ArcCoordsType);
Procedure GetAspectRatio(var Xasp, Yasp: Word);
Function GetBkColor: Word;
Function GetColor: Word;
Procedure GetDefaultPalette(var Palette: PaletteType);
Function GetDriverName: string;
Procedure GetFillPattern(var FillPattern: FillPatternType);
Procedure GetFillSettings(var FillInfo: FillSettingsType);
function GetGraphMode: Integer;
procedure GetImage(x1, y1, x2, y2: Integer; var BitMap);
Procedure GetLineSettings(var LineInfo: LineSettingsType);
Function GetMaxColor: Word;
Function GetMaxX: Word;
Function GetMaxY: Word;
Function GetModeName(ModeNumber: Integer): string;
Procedure GetPalette(var Palette: PaletteType);
Function GetPaletteSize: Integer;
Function GetPixel(X,Y: Integer): Word;
Procedure GetTextSettings(var TextInfo: TextSettingsType);
Procedure GetViewSettings(var ThisViewPort: ViewPortType);
Function GetX: Integer;
Function GetY: Integer;
Procedure GraphDefaults;
Function GraphErrorMsg(ErrorCode: Integer): String;
Function GraphResult: Integer;
function ImageSize(x1, y1, x2, y2: Integer): Word;
procedure InitGraph(var GraphDriver:Integer; var GraphMode: Integer;
PathToDriver: string);
Function InstallUserFont(FontFileName: string) : Integer;
Procedure Line(X1, Y1, X2, Y2: Integer);
Procedure LineRel(Dx, Dy: Integer);
Procedure LineTo(X, Y: Integer);
Procedure MoveRel(Dx, Dy: Integer);
Procedure MoveTo(X, Y: Integer);
Procedure OutText(TextString: string);
Procedure OutTextXY(X, Y: Integer; TextString: string);
Procedure PieSlice(X, Y: Integer; StAngle, EndAngle, Radius: Word);
procedure PutImage(X, Y: Integer; var BitMap; BitBlt: Word);
Procedure PutPixel(X, Y: Integer; Color: Word);
Procedure Rectangle(X1, Y1, X2, Y2: Integer);
Procedure RegisterBGIFont(FontID: Integer; Font: Pointer);
Procedure Sector(X, Y: Integer; StAngle, EndAngle, XRadius, YRadius: Word);
Procedure SetAllPalette(var Palette: PaletteType);
Procedure SetAspectRatio(Xasp, Yasp: Word);
Procedure SetBkColor(ColorNum: Word);
Procedure SetColor(Color: Word);
Procedure SetFillPattern(Pattern: FillPatternType; Color: Word);
Procedure SetFillStyle(Pattern: Word; Color: Word);
Procedure SetLineStyle(LineStyle: Word; Pattern: Word; Thickness: Word);
Procedure SetPalette(ColorNum: Word; Color: Byte);
Procedure SetRGBPalette(ColorNum: Word; Red, Green, Blue: Byte);
Procedure SetTextJustify(Horiz, Vert: Word);
Procedure SetTextStyle(Font, Direction, CharSize: Integer);
Procedure SetUserCharSize(MultX, DivX, MultY, DivY: Word);
Procedure SetViewPort(X1, Y1, X2, Y2: Integer; Clip: Boolean);
Procedure SetWriteMode(WriteMode: Integer);
Function TextHeight(TextString: string): Word;
Function TextWidth(TextString: string): Word;
// VP additional BGI functions
procedure SetWideFillPattern(Pattern: NewPatternType; Color: Word);
procedure VPInitGraph( xRes, yRes: Integer; PathToDriver: string);
procedure FlushDisplay; // Update BGI screen immediately
// VP functions for controlling the mouse
procedure GetMousePos( var x,y: Word );
function ReadKeyOrMouse( TimeOut: Word; var Mouse: Boolean;
var Key: Char; var MEvent: MouseEventT; var mx, my: Word ): Boolean;
function MouseClicked: Boolean;
procedure GetMouseEvent( var M: MouseEventRecT );
// VP functions replacing CRT functions
function Keypressed: Boolean; // Keypressed for both Server and Client
function ReadKey: Char;
// VP constants modifying behaviour of Graph
const
WaitKeypressed : Boolean = False; // Delay() when calling keypressed
AutoStartServer : Boolean = True; // Start BGI server proces in InitGraph
ImmediateUpdate : Boolean = True; // Process all requests immediately
MinFrameRate : Longint = 5; // Minimum frame rate
Implementation
uses Os2Def, Os2Base, Crt, Dos, VPUtils, BgiMsg, Mutex;
const
Stopping : boolean = false; // True when BGI is stopping
tid_BGI : tid = 0; // BGI Update Thread
tid_Kbd1 : tid = 0; // Local Keyboard watch thread
tid_Kbd2 : tid = 0; // Remote Keyboard watch thread
mtx_Kbd : tMutexSem = nil; // Keyboard mutex sem
mtx_Mou : tMutexSem = nil; // Mouse mutex sem
mtx_BGI : tMutexSem = nil; // BGI Update semaphore
KeyCount : Integer = 0; // Count of keys in KeyBuffer
MouCount : Integer = 0; // Count of event in MouBuffer
ServerSessionId : ULong = -1; // Process ID of GraphSrv
que_Input : HQueue = 0; // Queue ID for input queue
CurrentMouseX : Word = 0; // Current mouse position, X
CurrentMouseY : Word = 0; // Current mouse position, Y
var
F : File;
DispPtr : word;
DispList : DisplayListT;
com : CommandListT;
bgires : BGIResArT;
KeyBuffer : array[0..127] of Char; // Keyboard type-ahead buffer
MouBuffer : array[0..127] of MouseEventRecT; // Mouse input buffer
procedure waitforpipe;
var
cnt : Word;
res : word;
begin
if filerec(f).Handle > 0 then
exit;
// Create input queue used to capture input from BGI process
BGIQueueName[Length(BGIQueueName)+1] := #0;
Res := DosCreateQueue( que_input, que_fifo, @BGIQueueName[1] );
if Res <> No_Error then
raise EGraph.CreateFmt( 'Cannot connect to input queue; rc = ',[Res] );
// Connect to pipe
fileMode := open_Access_ReadWrite Or Open_Share_DenyReadWrite Or
Open_Flags_Fail_On_Error;
cnt:=0;
repeat
inc(cnt);
if cnt > 500 then
raise EGraph.Create( 'Cannot establish connection to Graph Server process' );
{$I-}
Reset(f,1);
{$I+}
res:=IOREsult;
if res<>0 then
DosSleep(50);
until Res=0;
end;
procedure ConnectionBroken;
const
Exited: Boolean = False;
var
Count: Longint;
rc: ApiRet;
begin
// Make sure function is not called by 2 threads
if Exited then Halt(1);
Exited := True;
// Release all semaphores
Mtx_BGI.Release;
Mtx_Kbd.Release;
Count := 0;
// Try to wait for server process to terminate so it can
// display any messages explaining the reason for the break
if ServerSessionId > 0 then
repeat
rc := DosSelectSession( ServerSessionId );
DosSleep( 50 );
inc( Count );
until (( rc <> Error_Smg_No_Target_Window ) and ( rc <> no_Error ) )
or ( Count > 50 );
// Raise exception, terminating both this and the server program
raise EGraph.Create( 'Connection to Graph Server process broken' );
end;
procedure flushdisplay;
var
ulRead : Word;
Res : Word;
rc : ApiRet;
begin
if DispPtr=0 then Exit;
mtx_BGI.Request;
if DispPtr=0 then
begin
// If display has been updated, exit
mtx_BGI.Release;
exit;
end;
rc := DosTransactNPipe( FileRec(F).Handle,
DispList, DispPtr*Sizeof(word),
// The following line works around an error in Os2Base.Pas:
Res, Sizeof(Res), Longint(@ulRead) );
// The following line should be used in the fixed Os2Base.Pas:
// Res, Sizeof(Res), ulRead );
if rc <> 0 then
ConnectionBroken;
DispPtr:=0;
mtx_BGI.Release;
end;
procedure askbgi(func,nrpar,nrret:word);
var
t,
ulRead : word;
snd : array [0..2] of word;
rc : ApiRet;
begin
flushdisplay;
mtx_BGI.Request;
DispList.w[DispPtr]:=func;
DispList.w[DispPtr+1]:=nrpar;
DispList.w[DispPtr+2]:=nrret;
for t:=0 to nrpar-1 do
DispList.i[DispPtr+t+3]:=com.i[t];
rc := DosTransactNPipe( FileRec(F).Handle,
DispList, (nrpar+3)*Sizeof(word),
// The following line works arounf an error in Os2Base.Pas:
BgiRes, NrRet*Sizeof(Word), Longint(@ulRead) );
// BgiRes, NrRet*Sizeof(Word), ulRead );
if rc <> 0 then
ConnectionBroken;
DispPtr:=0;
mtx_BGI.Release;
end;
procedure callbgi(func,nrpar:Word);
var
t : word;
begin
if ImmediateUpdate then
// Process all requests immediately - for animated graphics
askbgi( func, nrpar, 1 )
else
begin
// Process requests in chunks; lower overhead, but less
// pleasant for animated graphics
if DispPtr+NrPar+3>MaxDisp then
flushdisplay;
mtx_BGI.Request;
DispList.w[DispPtr]:=func;
DispList.w[DispPtr+1]:=nrpar;
DispList.w[DispPtr+2]:=0;
for t:=0 to nrpar-1 do
DispList.i[DispPtr+t+3]:=com.i[t];
DispPtr:=DispPtr+nrpar+3;
mtx_BGI.Release;
end;
end;
Procedure Arc(X, Y: Integer; StAngle, EndAngle, Radius: Word);
begin
com.i[0]:=x;com.i[1]:=y;
com.w[2]:=StAngle;com.w[3]:=EndAngle;com.w[4]:=Radius;
callbgi(1,5);
end;
Procedure Bar(X1, Y1, X2, Y2: Integer);
begin
com.i[0]:=x1;com.i[1]:=y1;
com.i[2]:=x2;com.i[3]:=y2;
callbgi(2,4);
end;
Procedure Bar3D(X1, Y1, X2, Y2: Integer; Depth: Word; Top: Boolean);
begin
com.i[0]:=x1;com.i[1]:=y1;
com.i[2]:=x2;com.i[3]:=y2;
com.w[4]:=Depth;if Top then com.w[5]:=1 else com.w[5]:=1;
callbgi(3,6);
end;
Procedure Circle(X, Y: Integer; Radius: Word);
begin
com.i[0]:=x;com.i[1]:=y;
com.w[2]:=Radius;
callbgi(4,3);
end;
Procedure ClearDevice;
begin
callbgi(5,0);
end;
Procedure ClearViewport;
begin
callbgi(6,0);
end;
Procedure CloseGraph;
begin
if tid_BGI = 0 then Exit;
callbgi(7,0); // CloseGraph() call to Server Process
Stopping := True;
DosWaitThread( tid_BGI, dcww_Wait );
tid_BGI := 0;
end;
procedure DetectGraph(var GraphDriver, GraphMode: Integer);
begin
askbgi(8,0,2);
GraphDriver:=bgires[0];GraphMode:=bgires[1];
end;
Procedure DrawPoly(NumPoints: Word; var PolyPoints);
begin
com.nr:=NumPoints;
move(PolyPoints,com.pts,2*NumPoints*SizeOf(integer));
callbgi(9,1+NumPoints*2);
end;
Procedure Ellipse(X, Y: Integer; StAngle, EndAngle: Word; XRadius, YRadius: Word);
begin
com.i[0]:=x;com.i[1]:=y;
com.w[2]:=stAngle;com.w[3]:=EndAngle;
com.w[4]:=XRadius;com.w[5]:=YRadius;
callbgi(10,6);
end;
Procedure FillEllipse(X, Y: Integer; XRadius, YRadius: Word);
begin
com.i[0]:=x;com.i[1]:=y;
com.w[2]:=XRadius;com.w[3]:=YRadius;
callbgi(11,6);
end;
Procedure FillPoly(NumPoints: Word; var PolyPoints);
begin
com.nr:=NumPoints;
move(PolyPoints,com.pts,2*NumPoints*SizeOf(integer));
callbgi(12,1+NumPoints*2);
end;
Procedure FloodFill(X, Y: Integer; Border: Word);
begin
com.x1:=x;com.y1:=y;com.w3:=border;
callbgi(13,3);
end;
Procedure GetArcCoords(var ArcCoords: ArcCoordsType);
begin
askbgi(14,0,6);
move(bgires,ArcCoords,sizeof(ArcCoords));
end;
Procedure GetAspectRatio(var Xasp, Yasp: Word);
begin
askbgi(15,0,2);
xasp:=bgires[0];yasp:=bgires[1];
end;
Function GetBkColor: Word;
begin
askbgi(16,0,1);
GetBkColor:=bgires[0];
end;
Function GetColor: Word;
begin
askbgi(17,0,1);
GetColor:=bgires[0];
end;
Procedure GetDefaultPalette(var Palette: PaletteType);
begin
askbgi(18,0,SizeOf(Palette) div Sizeof(word));
move(bgires,palette,sizeof(palette));
end;
Function GetDriverName: string;
var
s : string;
begin
askbgi(19,0,Sizeof(s) div Sizeof(word));
move(bgires,s,sizeof(s));
GetDrivername:=s;
end;
Procedure GetFillPattern(var FillPattern: FillPatternType);
begin
askbgi(20,0,Sizeof(FillPattern) div Sizeof(word));
move(bgires,fillpattern,sizeof(fillpattern));
end;
Procedure GetFillSettings(var FillInfo: FillSettingsType);
begin
askbgi(21,0,Sizeof(FillInfo) div Sizeof(word));
move(bgires,fillinfo,sizeof(fillinfo));
end;
function GetGraphMode: Integer;
begin
askbgi(22,0,1);
getgraphmode:=bgires[0];
end;
procedure GetImage(x1, y1, x2, y2: Integer; var BitMap);
var
Buffer: Pointer;
Bufsize: Longint;
rc: ApiRet;
begin
// Allocate shared memory region for transfer
BufSize := ImageSize( x1, y1, x2, y2 );
rc := DosAllocSharedMem( Buffer, nil, BufSize,
pag_read or pag_write or pag_commit or obj_gettable );
com.i[0]:=x1;com.i[1]:=y1;com.i[2]:=x2;com.i[3]:=y2;com.i[4]:=Longint(Buffer);
askbgi(23,5,1);
// Move image to user buffer
if bgires[0] = 0 then
move( Buffer^, BitMap, BufSize );
// Destroy shared memory area
rc := DosFreeMem( Buffer );
end;
Procedure GetLineSettings(var LineInfo: LineSettingsType);
begin
askbgi(24,0,Sizeof(LineInfo) div Sizeof(word));
move(bgires,lineinfo,sizeof(Lineinfo));
end;
Function GetMaxColor: Word;
begin
askbgi(25,0,1);
getmaxcolor:=bgires[0];
end;
Function GetMaxX: Word;
begin
askbgi(26,0,1);
getmaxx:=bgires[0];
end;
Function GetMaxY: Word;
begin
askbgi(27,0,1);
getmaxy:=bgires[0];
end;
Function GetModeName(ModeNumber: Integer): string;
var
s : string;
begin
com.i1:=ModeNumber;
askbgi(28,1,Sizeof(s) div Sizeof(word));
move(bgires,s,sizeof(s));
GetModename:=s;
end;
Procedure GetPalette(var Palette: PaletteType);
begin
askbgi(29,0,Sizeof(Palette) div Sizeof(word));
move(bgires,palette,sizeof(Palette));
end;
Function GetPaletteSize: Integer;
begin
askbgi(30,0,1);
GetPaletteSize:=bgires[0];
end;
Function GetPixel(X,Y: Integer): Word;
begin
com.x1:=x;com.y1:=y;
askbgi(31,2,1);
getpixel:=bgires[0];
end;
Procedure GetTextSettings(var TextInfo: TextSettingsType);
begin
askbgi(32,0,Sizeof(textInfo) div Sizeof(word));
move(bgires,textinfo,sizeof(textinfo));
end;
Procedure GetViewSettings(var ThisViewPort: ViewPortType);
begin
askbgi(33,0,Sizeof(ThisViewPort) div Sizeof(word));
move(bgires,ThisViewPort,sizeof(ThisViewPort));
end;
Function GetX: Integer;
begin
askbgi(34,0,1);
getx:=bgires[0];
end;
Function GetY: Integer;
begin
askbgi(35,0,1);
gety:=bgires[0];
end;
Procedure GraphDefaults;
begin
flushdisplay;
callbgi(36,0);
end;
Function GraphErrorMsg(ErrorCode: Integer): String;
begin
GraphErrorMsg:='';
end;
Function GraphResult: Integer;
begin
flushdisplay;
graphresult:=0;
end;
function ImageSize(x1, y1, x2, y2: Integer): Word;
begin
// Don't ask BGI about a multiplication
ImageSize := (x2-x1+1)*(y2-y1+1)+6;
end;
procedure PushKey(Ch: Char);
begin
mtx_Kbd.Request;
if KeyCount < SizeOf(KeyBuffer) then
begin
KeyBuffer[KeyCount] := Ch;
Inc(KeyCount);
end;
mtx_Kbd.Release;
end;
procedure PushMouse( MouEvent: MouseEventT; MouX,MouY: Word);
begin
mtx_Mou.Request;
if MouCount < SizeOf(MouBuffer) then
with MouBuffer[MouCount] do
begin
Event := MouEvent;
X := MouX;
Y := MouY;
Inc(MouCount);
end;
mtx_Mou.Release;
end;
function MouseClicked: Boolean;
begin
MouseClicked := MouCount > 0;
end;
procedure GetMouseEvent( var M: MouseEventRecT );
begin
while not MouseClicked do
DosSleep( 31 );
mtx_Mou.Request;
M := MouBuffer[0];
Dec( MouCount );
move( MouBuffer[1], MouBuffer[0], MouCount*Sizeof(MouBuffer[0]) );
mtx_Mou.Release;
end;
function Keypressed: Boolean;
begin
KeyPressed := KeyCount > 0;
If ( KeyCount = 0 ) and (WaitKeypressed or (DispPtr > 100)) then
// if no key was waiting, pause thread to allow update of
// screen, if WaitKeyPressed or many items to be processed
DosSleep( 1 );
end;
function ReadKey: Char;
begin
while not KeyPressed do
// If Keypressed did not wait, wait here
if not WaitKeyPressed then
DosSleep( 31 );
mtx_Kbd.Request;
ReadKey := KeyBuffer[0];
Dec(KeyCount);
Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
mtx_Kbd.Release;
end;
// Thread updating display at least MinFrameRate times per second
function BGIUpdateThread( p: Pointer ): Longint;
begin
while not Stopping do
begin
if DispPtr <> 0 then
FlushDisplay;
DosSleep( 1000 div MinFrameRate );
end;
end;
// Thread routing keyboard input TXT screen
function BGILocalKeyboardThread( p: Pointer ): Longint;
begin
While not Stopping do
// Add next keystroke to BGI buffer
PushKey( Crt.Readkey )
end;
// Thread routing keyboard input from BGI screen
function BGIRemoteKeyboardThread( p: Pointer ): Longint;
var
RData: RequestData;
cbData: ULong;
Buffer: Pointer;
Priority: Byte;
rc: ApiRet;
begin
While not Stopping do
begin
// Wait for key to be pressed in BGI window
rc := DosReadQueue( que_input, RData, cbData, Buffer, 0,
dcww_Wait, Priority, 0 );
// If succesful, add to BGI buffer
if rc = 0 then
case RData.Data of
bgi_Init : DosGetSharedMem( Buffer, pag_Read );
bgi_Key : PushKey( InputT(Buffer^).Ch );
bgi_MPos : with InputT(Buffer^) do
begin
CurrentMouseX := X;
CurrentMouseY := Y;
end;
bgi_Mou : with InputT(Buffer^) do
PushMouse( MouseEventT(EventType), EventX, EventY );
end
end;
end;
// Make checks to see if DIVE is installed and if it is
// the buggy version from Warp or a newer one
procedure VerifyDiveVersion;
const
initErr: pChar = 'GRAPH initialization error';
var
rc: Longint;
Buffer: array[0..259] of Char;
dll_Dive: Longint;
s: String;
Age: Longint;
Date: TDateTime;
Year, Month, Day: SmallWord;
begin
rc := DosLoadModule(Buffer, SizeOf(Buffer), 'DIVE', dll_Dive);
if rc <> 0 then
raise EGraph.Create( 'Dive not installed on system. Application terminated' );
rc := DosQueryModuleName( dll_Dive, Sizeof(Buffer), Buffer );
if rc <> 0 then
raise EGraph.CreateFmt( 'Cannot load DIVE.DLL; rc = %d. Application terminated', [rc] );
Age := FileAge( StrPas( Buffer ) );
Date := FileDateToDateTime( Age );
DecodeDate(Date, Year, Month, Day);
If Year < 1995 then
raise EGraph.Create( 'DIVE installed is very outdated and cannot be used' );
DosFreeModule( dll_Dive );
end;
procedure _InitGraph( xRes, yRes: Integer; const PathToDriver: string);
var
rc: ApiRet;
SD: StartData;
IdProcess : ULong;
s: String;
Count: Longint;
CommName: String;
begin
DispPtr:=0;
// if AutoStartServer is false, the BGI server process must be started
// manually by executing GRAPHSRV.EXE.
if AutoStartServer then
begin
// First verify presence of DIVE, copying routine from Os2Dive
VerifyDiveVersion;
// Set up unique pipe name to allow multiple instances of
// this program to run safely
CommName := 'BGI'+ // Pipe prefix
Int2Hex( GetForegroundProcessID, 4 )+ // Process ID
Int2Hex( GetTimeMSec, 8 ); // Time in ms
BGIPipeName := '\PIPE\'+CommName;
BGIQueueName := '\QUEUES\'+CommName;
s := Format( '/B%s /P%s /X%d /Y%d'#0, [PathToDriver, BGIPipeName, xres, yres] );
// Spawn Graph Server process
fillchar( sd, sizeof(sd), 0 );
with SD do
begin
Length := sizeof(StartData);
Related := ssf_Related_Child;
FgBg := ssf_FgBg_Fore;
TraceOpt := ssf_TraceOpt_None;
PgmTitle := 'VP/2 BGI Graphics Server Process';
PgmName := 'graphsrv.exe';
PgmInputs := @s[1];
TermQ := nil;
Environment := nil;
InheritOpt := ssf_InhertOpt_Parent;
SessionType := ssf_Type_Pm;
IconFile := nil;
PgmHandle := 0;
PgmControl := ssf_Control_Visible;
end;
rc := DosStartSession( SD, ServerSessionId, IdProcess );
if ( rc <> No_Error ) and ( rc <> error_Smg_Start_In_Background ) then
begin
Writeln( 'Graph Server Process GRAPHSRV.EXE not found' );
halt(1);
end;
end; // If AutoStartServer
{$I-}
Close(f);
Assign(f,BGIPipeName);
{$I+}
if ioresult <> 0 then ;
WaitForPipe;
Stopping := False;
// Start thread for trigging regular screen update
tid_BGI := VPBeginThread( BGIUpdateThread, 16384, nil );
DosSetPriority( prtys_thread, prtyc_timecritical, 0, tid_BGI );
// Start thread for watching the local keyboard
tid_Kbd1 := VPBeginThread( BGILocalKeyboardThread, 8192, nil );
// Start thread for watching the remote keyboard
tid_Kbd2 := VPBeginThread( BGIRemoteKeyboardThread, 8192, nil );
GraphDefaults;
ClearDevice;
end;
procedure InitGraph(var GraphDriver:Integer; var GraphMode: Integer;
PathToDriver: string);
begin
_InitGraph( 640, 480, PathToDriver );
end;
Function InstallUserFont(FontFileName: string) : Integer;
begin
com.s:=fontfilename;
askbgi(41,3,1);
InstallUserFont:=bgires[0];
end;
Procedure Line(X1, Y1, X2, Y2: Integer);
begin
com.i[0]:=x1;com.i[1]:=y1;
com.i[2]:=x2;com.i[3]:=y2;
callbgi(42,4);
end;
Procedure LineRel(Dx, Dy: Integer);
begin
com.i[0]:=dx;com.i[1]:=dy;
callbgi(43,2);
end;
Procedure LineTo(X, Y: Integer);
begin
com.i[0]:=x;com.i[1]:=y;
callbgi(44,2);
end;
Procedure MoveRel(Dx, Dy: Integer);
begin
com.i[0]:=dx;com.i[1]:=dy;
callbgi(45,2);
end;
Procedure MoveTo(X, Y: Integer);
begin
com.i[0]:=x;com.i[1]:=y;
callbgi(46,2);
end;
Procedure OutText(TextString: string);
begin
com.i[0]:=0;com.i[1]:=0;
com.s:=TextString;
callbgi(47,3+(length(TextString) div sizeof(word)));
end;
Procedure OutTextXY(X, Y: Integer; TextString: string);
begin
com.i[0]:=x;com.i[1]:=y;
com.s:=TextString;
callbgi(48,3+(length(TextString) div sizeof(word)));
end;
Procedure PieSlice(X, Y: Integer; StAngle, EndAngle, Radius: Word);
begin
com.i[0]:=x;com.i[1]:=y;
com.w[2]:=StAngle;com.w[3]:=EndAngle;com.w[4]:=Radius;
callbgi(49,5);
end;
procedure PutImage(X, Y: Integer; var BitMap; BitBlt: Word);
var
Buffer: pChar;
Bufsize: Longint;
rc: ApiRet;
begin
// Allocate shared memory region for transfer
Buffer := @Bitmap;
BufSize := pSmallWord(Buffer)^; inc(Buffer,sizeof(smallword));
BufSize := BufSize*pSmallWord(Buffer)^+6;
rc := DosAllocSharedMem( Pointer(Buffer), nil, BufSize,
pag_read or pag_write or pag_commit or obj_gettable );
// Move image to user buffer and transfer to BGI server
move( BitMap, Buffer^, BufSize );
com.x:=x;com.y:=y;com.Buffer:=Buffer;com.m:=BitBlt;
askbgi(50,4,1);
// Destroy shared memory area
rc := DosFreeMem( Buffer );
end;
Procedure PutPixel(X, Y: Integer; Color: Word);
begin
com.i[0]:=x;com.i[1]:=y;com.w3:=Color;
callbgi(51,3);
end;
Procedure Rectangle(X1, Y1, X2, Y2: Integer);
begin
com.i[0]:=x1;com.i[1]:=y1;
com.i[2]:=x2;com.i[3]:=y2;
callbgi(52,4);
end;
Procedure RegisterBGIFont(FontID: Integer; Font: Pointer);
begin
com.i1:=fontid;com.w2:=word(font);
callbgi(53,2);
end;
Procedure Sector(X, Y: Integer; StAngle, EndAngle, XRadius, YRadius: Word);
begin
com.i[0]:=x;com.i[1]:=y;
com.w[2]:=StAngle;com.w[3]:=EndAngle;
com.w[4]:=XRadius;com.w[5]:=YRadius;
callbgi(54,6);
end;
Procedure SetAllPalette(var Palette: PaletteType);
begin
move(palette,com.i[0],sizeof(Palette));
callbgi(55,Sizeof(Palette) div Sizeof(word));
end;
Procedure SetAspectRatio(Xasp, Yasp: Word);
begin
com.w1:=xasp;com.w2:=yasp;
callbgi(56,2);
end;
Procedure SetBkColor(ColorNum: Word);
begin
com.w[0]:=ColorNum;
callbgi(57,1);
end;
Procedure SetColor(Color: Word);
begin
com.w[0]:=Color;
callbgi(58,1);
end;
Procedure SetFillPattern(Pattern: FillPatternType; Color: Word);
begin
com.w1:=color;move(Pattern,com.w[1],sizeof(Pattern));
callbgi(59,1+(sizeof(Pattern) div Sizeof(word)));
end;
Procedure SetFillStyle(Pattern: Word; Color: Word);
begin
com.w[0]:=Pattern;
com.w[1]:=Color;
callbgi(60,2);
end;
Procedure SetLineStyle(LineStyle: Word; Pattern: Word; Thickness: Word);
begin
com.w[0]:=LineStyle;
com.w[1]:=Pattern;
com.w[2]:=Thickness;
callbgi(61,3);
end;
Procedure SetPalette(ColorNum: Word; Color: Byte);
begin
com.w1:=colornum;
com.w2:=color;
callbgi(62,2);
end;
Procedure SetRGBPalette(ColorNum: Word; Red, Green, Blue: Byte);
begin
com.w1:=colornum;
com.w2:=red;com.w3:=green;com.w4:=blue;
callbgi(63,4);
end;
Procedure SetTextJustify(Horiz, Vert: Word);
begin
com.w[0]:=Horiz;
com.w[1]:=Vert;
callbgi(64,2);
end;
Procedure SetTextStyle(Font, Direction, CharSize: Integer);
begin
com.i[0]:=Font;
com.i[1]:=Direction;
com.i[2]:=CharSize;
callbgi(65,3);
end;
Procedure SetUserCharSize(MultX, DivX, MultY, DivY: Word);
begin
com.w1:=multx;
com.w2:=divx;
com.w3:=multy;
com.w4:=divy;
callbgi(66,4);
end;
Procedure SetViewPort(X1, Y1, X2, Y2: Integer; Clip: Boolean);
begin
com.x1:=x1;
com.y1:=y1;
com.x2:=x2;
com.y2:=y2;
if clip then com.w5:=1 else com.w5:=0;
callbgi(67,5);
end;
Procedure SetWriteMode(WriteMode: Integer);
begin
com.i[0]:=WriteMode;
callbgi(68,1);
end;
Function TextHeight(TextString: string): Word;
begin
com.s:=TextString;
askbgi(69,3+(length(TextString) div sizeof(word)),1);
textHeight:=bgires[0];
end;
Function TextWidth(TextString: string): Word;
begin
com.s:=TextString;
askbgi(70,3+(length(TextString) div sizeof(word)),1);
textWidth:=bgires[0];
end;
// VP additional BGI functions
procedure SetWideFillPattern(Pattern: NewPatternType; Color: Word);
begin
com.w1:=color;move(Pattern,com.w[1],sizeof(Pattern));
callbgi(71,1+(sizeof(Pattern) div Sizeof(word)));
end;
procedure VPInitGraph( xRes, yRes: Integer; PathToDriver: string);
begin
_InitGraph( xRes, yRes, PathToDriver );
end;
procedure GetMousePos( var x,y: Word );
begin
x := CurrentMouseX;
y := CurrentMouseY;
end;
function ReadKeyOrMouse( TimeOut: Word; var Mouse: Boolean;
var Key: Char; var MEvent: MouseEventT; var mx, my: Word ): Boolean;
var
M: MouseEventRecT;
StartTime: Integer;
begin
ReadKeyOrMouse := True;
StartTime := GetTimemSec;
repeat
if keypressed then
begin
Mouse := False;
Key := Readkey;
Exit;
end
else if MouseClicked then
begin
Mouse := True;
GetMouseEvent( M );
MEvent := M.Event;
mx := M.X;
my := M.Y;
Exit;
end
else
DosSleep( 31 );
// Repeat until timeout. Timeout = -1 means indefinite wait
until (TimeOut <> -1) and (GetTimeMSec - StartTime > TimeOut);
ReadKeyOrMouse := False;
end;
initialization
// Write exceptions to user screen
SysUtils.PopUpErrors := false;
// Create multiplex semaphores
mtx_BGI := tMutexSem.Create;
mtx_Kbd := tMutexSem.Create;
mtx_Mou := tMutexSem.Create;
end.