home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
vpbgib2.zip
/
OS2DIVE.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-11-02
|
75KB
|
2,266 lines
{█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█}
{█ █}
{█ Virtual Pascal Examples Version 1.1 █}
{█ DIVE Class - Beta 2 █}
{█ ─────────────────────────────────────────────────█}
{█ Copyright (C) 1996 fPrint UK Ltd █}
{█ Written May 1996 by Allan Mertner █}
{█ Inspired by DIVERace by Michael Mrosowski █}
{█ █}
{▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
{$Delphi+}
unit Os2Dive;
{$IFDEF VER10}
!! This unit requires a version of Virtual Pascal later than 1.00
{$ENDIF}
interface
uses
Os2Def, Os2Base, Os2mm, Os2PmApi, // OS/2 API definitions
Use32, VPUtils, SysUtils, Mutex; // Utility libraries
const
// Standard menu commands handled by default msg handler
ID_DIVEMENU = 1000;
ID_NEWTEXT = 1001;
ID_SNAP = 1002;
ID_SNAP2 = 1003;
ID_SNAPFULL = 1004;
ID_EXIT = 1005;
ID_PAUSE = 1006;
ID_SETCOLOR = 2000;
const
// Maximum display size
xmax = 1279;
ymax = 1023;
FastBlitSupported : Boolean = True;
SuppressMessages : Boolean = False;
type
Pixel = Record
x,y: Integer;
end;
tRect = Record
x1,y1, x2,y2: Integer;
end;
type
DisplayBufferArray = Array[ 0..(ymax+1)*(xmax+1)-1 ] of Byte;
pDisplayBufferArray = ^DisplayBufferArray;
tDiveWindow = class;
tUpdateFunc = Procedure( Dive: tDiveWindow );
ArcCoorType = record
X : Integer;
Y : Integer;
Xstart : Integer;
Ystart : Integer;
Xend : Integer;
Yend : Integer;
end;
EDive = class(Exception);
EDiveDraw = class(EDive);
tDiveWindow = class
private
ScreenX: LongInt;
ScreenY: LongInt;
hDive: HDive;
fImage: Longint;
fSizeX: Longint;
fSizeY: Longint;
fccColorFormat : Longint;
fLineSize: Longint;
hwndClient: HWnd;
fColorBits: Byte;
tidBlitThread: tid;
tidTimerThread: tid;
tidPaletteThread: tid;
TimerEvent: Hev;
fStopping: Boolean;
fDisplayBuf: pDisplayBufferArray;
fUpdateBuffer: tUpdateFunc;
fMessageHandler: fnWP;
fLineMode: Boolean;
fPauseDisplay: Boolean;
pPalette: Pointer;
PaletteChanged: Set of 0..255;
pChanged: Boolean;
fChanged: Boolean;
fChangedRect: RectL;
OldPal: HPs;
PSPal: HPS;
SetupBlitter : SETUP_BLITTER;
mtx_Update: tMutexSem;
mtx_Rect: tMutexSem;
mtx_Palette: tMutexSem;
LineThickness: Word;
LinePattern: Word; // Pattern for line drawing
fVP: tRect; // Current ViewPort
fVPClip: Boolean; // Clipping mode
fxAspect: Integer; // Aspect settings
fyAspect: Integer;
PatternInx: Integer;
fFastBlit: Boolean;
Procedure SetMainWindowTitle( s: string );
protected
hwndFrame: HWnd;
LastArc: ArcCoorType;
Procedure SetPaletteArray;
function GetColours: Longint;
procedure InitWindow( ResType, ResID: Longint ); virtual;
function GetPix(x,y: Longint): Longint;
procedure SetPix(x,y: Longint; Value: Longint);
function BeginUpdate: Integer;
procedure EndUpdate;
property DisplayBuffer: pDisplayBufferArray read fDisplayBuf;
procedure SetRGBColor( Num: Word; red,green,blue: byte );
// ViewPort functions; take native x,y coordinates
function GetWinPix(x,y: Longint): Longint;
procedure SetWinPix(x,y, Value: Longint );
function VPBufAdr( x,y: Integer ): Integer;
function VPTransformXY( var x, y: Integer ): Boolean;
procedure VPTransformXXY( var xa, xb, y: Integer );
procedure VPTransformXYXY( var xa, ya, xb, yb: Integer );
procedure PixelChanged( x,y: Integer );
function VPWidth: Integer;
function VPHeight: Integer;
function VPXMax: Integer;
function VPYMax: Integer;
procedure SetViewPort( xa, ya, xb, yb: Integer );
procedure FillLine( x1,x2,y,c: Longint );
public
FillPattern: Array[0..15] of SmallWord;
FillColor: Word;
FillBkColor: Word;
LinePutMode: Integer;
// Constructors and destructors
constructor Create( SizeX, SizeY: Longint; ColorBits: Byte );
constructor CreateRes( SizeX, SizeY: Longint; ColorBits: Byte; ResType, ResID: Longint );
destructor Destroy; override;
// Message handling loop
procedure run; virtual;
// Properties of the window as a whole
property Colours: Longint read GetColours;
property Stopping: Boolean read fStopping write fStopping;
property xSize: Longint read fSizeX;
property ySize: Longint read fSizeY;
property PauseDisplay: Boolean read fPauseDisplay write fPauseDisplay;
property ImageChanged: Boolean read fChanged write fChanged;
procedure RectChanged( x1,y1, x2,y2: Integer );
procedure AllChanged;
property ViewPort: tRect read fVP write fVP;
property VPClip: Boolean read fVPClip write fVPClip;
property xAspect: Integer read fxAspect write fxAspect;
property yAspect: Integer read fyAspect write fyAspect;
procedure WaitDraw; // Wait until refresh has occured
procedure SetLineThickness( Thickness: Word );
procedure SetLinePattern( Pattern: Word );
property FastBlit: boolean read fFastBlit write fFastBlit;
// User hooks
property UpdateBuffer: tUpdateFunc read fUpdateBuffer write fUpdateBuffer;
property MessageHandler: FNWp read fMessageHandler write fMessageHandler;
// Drawing primitives
procedure Clear( Col: Longint );
property LineMode: Boolean read fLineMode write fLineMode;
function FillPatternColor( x, y: Integer ): Integer;
// All Draw* procedures take coordinates within ViewPort
property Pixels[x,y:Longint]: longint read GetPix write SetPix; default;
procedure DrawLine( x1,y1, x2,y2, c: Longint );
procedure DrawFillLine( x1,x2,y: Integer );
procedure DrawBox( x1,y1, x2,y2, c: Longint );
procedure DrawFillRect( x1,y1, x2,y2, c: Longint );
procedure DrawTriangle( p1,p2,p3: Pixel; c: Longint );
procedure DrawQuad( p1,p2,p3,p4: Pixel; c: Longint );
Procedure DrawStr( x, y, col, BackCol: Integer; s: String );
Procedure DrawArc( Center: Pixel; Rad, StAngle, EndAngle, Col: Integer );
Procedure DrawEllipse( Center: Pixel; XRad, YRad, StAngle, EndAngle, Col: Integer );
Procedure DrawPieSlice( Center: Pixel; Rad, StAngle, EndAngle, Col: Integer );
Procedure Flip( Steps: Longint );
end;
const
coltranslate : boolean = true; // Translate 256 Colors for Dive ?
var
tSin,tCos : array[0..4*360] of Integer;
h_ab : Longint;
{$IFDEF DEBUG}
procedure log( s: String );
{$ENDIF}
implementation
{$IFDEF DEBUG}
var
logfile:text;
mtx_log: HMtx;
procedure log( s: String );
begin
dosrequestmutexsem( mtx_log, sem_indefinite_wait );
append(logfile);
writeln(logfile,format( 'ID %d: %s', [ GetThreadID, s] ));
close(logfile);
dosreleasemutexsem( mtx_log );
end;
{$ENDIF}
type
t_rgbx = record
case boolean of
true: (b,g,r,x:byte);
false:(l:Longint);
end;
t_rgbxpal8 = array[0..255] of t_rgbx;
p_rgbxpal8 = ^t_rgbxpal8;
const
FourCC_LUT8 = ord('L')+(ord('U') shl 8)+(ord('T') shl 16)+(ord('8') shl 24);
FourCC_R565 = ord('R')+(ord('5') shl 8)+(ord('6') shl 16)+(ord('5') shl 24);
FourCC_BGR4 = ord('B')+(ord('G') shl 8)+(ord('R') shl 16)+(ord('4') shl 24);
FourCC_SCRN = 0;
pszMyWindow:Pchar = 'DiveWindow';
pszTitleText:Pchar = 'Dive Window';
var
h_dc : hDC;
h_pal:HPAL;
var achTitle: array[0..255] of char;
Procedure tDiveWindow.SetMainWindowTitle(s:string);
begin
StrPCopy( @achTitle, s );
WinPostMsg ( hwndFrame, WM_COMMAND, ID_NEWTEXT, longint(@achTitle));
end;
Function GetSnapHeight(ulHeight:ULONG):ULONG;
begin
Inc( ulHeight, WinQuerySysValue ( HWND_DESKTOP, SV_CYSIZEBORDER ) * 2);
{ Inc( ulHeight, WinQuerySysValue ( HWND_DESKTOP, SV_CYBORDER ) * 2);
Inc( ulHeight, WinQuerySysValue ( HWND_DESKTOP, SV_CYMENU )*2 );}
Inc( ulHeight, WinQuerySysValue ( HWND_DESKTOP, SV_CYTITLEBAR ) );
GetSnapHeight:=ulHeight;
end;
Function GetSnapWidth(ulWidth:ULONG):ULONG;
begin
Inc( ulWidth, WinQuerySysValue ( HWND_DESKTOP, SV_CXSIZEBORDER ) * 2);
GetSnapWidth:=ulWidth;
end;
function MyWindowProc(Window: HWnd; Msg: ULong; Mp1,Mp2: MParam): MResult;cdecl;
const
h_psPal :HPS = 0; (* Presentation Space handle *)
test:longint = $303030;
var
point_l :POINTL; (* Point to offset from Desktop *)
swpos :SWP; (* Window position *)
h_rgn :HRGN; (* Region handle *)
h_ps :HPS; (* Presentation Space handle *)
rcls :array[0..49] of RECTL;(* Rectangle coordinates *)
rgnCtl :RGNRECT; (* Processing control structure *)
MyDive :tDiveWindow;
pPal :PLONG;
NoRectl :PRECTL;
PaletteColors:ULONG;
xwidth : uLong;
yHeight : uLong;
sizl:SIZEL;
rc:Ulong;
ColorTable: p_rgbxpal8;
p:pChar;
begin
NoRectl:=Nil;
MyDive:= tDiveWindow(WinQueryWindowULong (Window, 0));
// Run user's message handler first
If ( MyDive <> nil ) and Assigned( MyDive.MessageHandler ) then
begin
Result := MyDive.MessageHandler( Window, Msg, mp1, mp2 );
If Result <> 0 then
// Message handled by user
Exit;
end;
if (MyDive <> nil) or (msg=WM_CREATE) then begin
case msg of
WM_CREATE:
winPostMsg( Window, 11111, 0, 0 );
11111:
begin
// Set Up the physical palette
sizl.cx := 0;
sizl.cy := 0;
h_DC := WinOpenWindowDC(Window);
h_psPal := GpiCreatePS(h_ab,h_dc,sizl,
PU_PELS or GPIF_DEFAULT or GPIT_MICRO or GPIA_ASSOC);
h_pal := GpiQueryPalette( h_pspal );
// GpiQueryPaletteInfo( h_pal, h_pspal, 0, 0, 16, uLong( MyDive.pPalette^ ) );
end;
WM_COMMAND:
case USHORT(mp1) of
ID_SETCOLOR:
begin
DiveSetSourcePalette ( MyDive.hDive,
Short2FromMP(mp1),
1,
@mp2 );
end;
ID_SNAP:
// Snap Window to Dive Buffer Size
WinSetWindowPos ( MyDive.hwndFrame, HWND_TOP,
0, 0, // Ignored
GetSnapWidth( MyDive.xsize ),
GetSnapHeight( MyDive.ySize ),
SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
ID_SNAP2:
// Snap Window to Size & height * 2
With MyDive do
begin
xWidth := xSize+GetSnapWidth( xSize );
yHeight := ySize+GetSnapHeight( ySize );
WinSetWindowPos ( hwndFrame, HWND_TOP,
(ScreenX-xWidth) div 2, (ScreenY-yHeight) div 2,
xWidth, yHeight,
SWP_MOVE or SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
end;
ID_SNAPFULL:
// Snap to Full Size but retain (approx) aspect ratio
With MyDive do
begin
yHeight := (fSizeY*ScreenX) div fSizeX;
WinSetWindowPos ( hwndFrame, HWND_TOP,
0, (screenY-yHeight) div 2,
ScreenX, yHeight,
SWP_MOVE or SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
end;
ID_EXIT:
// Post to quit the dispatch message loop.
WinPostMsg ( Window, WM_QUIT, 0, 0 );
ID_PAUSE:
// Pause by stopping timer thread
with MyDive do
begin
PauseDisplay := not PauseDisplay;
If PauseDisplay then
SetMainWindowTitle('PAUSED')
else
SetMainWindowTitle('Resumed');
end;
ID_NEWTEXT:
// Write new text string to the title bar
WinSetWindowText ( MyDive.hwndFrame, PCHAR(mp2) );
else
begin
// Let PM handle this message.
MyWindowProc := WinDefWindowProc ( Window, msg, mp1, mp2 );
exit;
end;
end; // WM_COMMAND
WM_VRNDISABLED:
DiveSetupBlitter ( MyDive.hDive, nil );
WM_VRNENABLED:
begin
h_ps := WinGetPS ( Window );
if h_ps<>0 then begin
h_rgn := GpiCreateRegion ( h_ps, 0, NoRectl^ );
if h_rgn<>0 then begin
WinQueryVisibleRegion ( Window, h_rgn );
rgnCtl.ircStart := 0;
rgnCtl.crc := 50;
rgnCtl.ulDirection := 1;
// Get the all ORed rectangles
if GpiQueryRegionRects ( h_ps, h_rgn, NoRectl^, rgnCtl, rcls[0]) then
begin
// Now find the window position and size, relative to parent.
WinQueryWindowPos ( MyDive.hwndClient, swpos );
// Convert the point to offset from desktop lower left.
point_l.x := swpos.x;
point_l.y := swpos.y;
WinMapWindowPoints ( MyDive.hwndFrame,
HWND_DESKTOP, point_l, 1 );
// Tell DIVE about the new settings.
With MyDive.SetupBlitter do
begin
ulStructLen := sizeof ( SETUP_BLITTER );
fccSrcColorFormat := MyDive.fccColorFormat;
ulSrcWidth := MyDive.fSizeX;
ulSrcHeight := MyDive.fSizeY(* shr 1*);
ulSrcPosX := 0;
ulSrcPosY := 0;
fInvert := FALSE (*TRUE*);
ulDitherType := 0;
if coltranslate then
fccDstColorFormat := FourCC_Scrn
else
fccDstColorFormat := FOURCC_LUT8;
ulDstWidth := swpos.cx;
ulDstHeight := swpos.cy(*shr 1*);
lDstPosX := 0;
lDstPosY := 0;
lScreenPosX := point_l.x;
lScreenPosY := point_l.y;
ulNumDstRects := rgnCtl.crcReturned;
pVisDstRects := @rcls;
end; // With
rc := DiveSetupBlitter ( MyDive.hDive, @MyDive.SetupBlitter );
if rc <> 0 then
raise EDive.CreateFmt( 'Cannot setup DIVE blitter; rc = %d', [rc] );
end
else
begin
rc := DiveSetupBlitter ( MyDive.hDive, nil );
if rc <> 0 then
raise EDive.CreateFmt( 'Cannot setup DIVE blitter; rc = %d', [rc] );
end;
GpiDestroyRegion( h_ps, h_rgn );
end;
end;
end; // WM_VRNENABLED
WM_REALIZEPALETTE:
begin
{ h_ps := WinBeginPaint ( MyDive.hwndFrame, 0 , Nil);
GetMem(pPal,sizeof(LONG) * MyDive.Colours );
GpiQueryRealColors ( h_ps, 0, 0, MyDive.Colours, pPal^ );
if coltranslate then
DiveSetDestinationPalette ( MyDive.hDive, 0,
MyDive.Colours,
Pointer(pPal));
FreeMem(pPal,sizeof(LONG) * MyDive.Colours);
WinEndPaint ( h_ps );}
end;
WM_CHAR :
// Handle default hotkeys
if (CharMsgMp1(Mp1).fs and kc_KeyUp) = 0 then { Key is Down }
case uShort(mp2 shr 16) of
VK_F2 : WinPostMsg ( Window, WM_COMMAND, ID_SNAP2, 0 );
VK_F3 : WinPostMsg ( Window, WM_QUIT, 0, 0 );
VK_F4 : WinPostMsg ( Window, WM_COMMAND, ID_SNAPFULL, 0 );
VK_F5 : WinPostMsg ( Window, WM_COMMAND, ID_PAUSE, 0 );
VK_F6 : WinPostMsg ( Window, WM_COMMAND, ID_SNAP, 0 );
end;
WM_SIZE, WM_ERaSEBACKGROUND:
begin
MyDive.AllChanged;
MyWindowProc := WinDefWindowProc ( Window, msg, mp1, mp2 );
end;
WM_CLOSE:
begin
// Post to quit the dispatch message loop.
GpiSelectPalette(h_psPal,0);
GpiDeletePalette(h_pal);
GpiDestroyPS(h_psPal);
WinPostMsg ( Window, WM_QUIT, 0, 0 );
end;
else
begin
// Let PM handle this message.
MyWindowProc := WinDefWindowProc ( Window, msg, mp1, mp2 );
exit;
end;
end; { Case msg }
end
else
begin
// Let PM handle this message.
MyWindowProc := WinDefWindowProc ( Window, msg, mp1, mp2 );
exit;
end;
MyWindowProc:=0;
end;
function GetTime: Longint;
begin
DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, Result, 4 );
end;
Function TimerThread( P: Pointer ): Longint;
var
rc: ApiRet;
begin
with tDiveWindow(p) do
While not stopping do
begin
rc := DosPostEventSem( TimerEvent );
if rc = 6 then exit;
DosSleep(50);
// If paused, delay until unpaused or exit
While PauseDisplay and not Stopping do
DosSleep(100);
end;
end;
Function BlitterThread( P: Pointer ): Longint;
var
MyDive : tDiveWindow;
rc : ApiRet;
PostCount : Longint;
NewBlitter : Setup_Blitter;
swpos : SWP; // Window position
point_l : POINTL; // Point to offset from Desktop
xRatio : Double;
yRatio : Double;
RoundUpX : Longint;
RoundUpY : Longint;
DeltaY : Longint;
begin
MyDive := tDiveWindow( P );
// Set up colour palette
if ColTranslate then
With MyDive do
DiveSetSourcePalette ( hDive, 0, Colours, pPalette );
try
With MyDive do
While not Stopping do
begin
If Assigned( UpdateBuffer ) then
if BeginUpdate = 0 then
begin
// Call user function to update buffer content
UpdateBuffer( MyDive );
EndUpdate;
end;
if not PauseDisplay then
begin
mtx_Rect.Request;
// Make image appear in window
if fChanged then
begin
mtx_Update.Request;
if FastBlit then
begin
// Accelerated blit routine
WinQueryWindowPos ( hwndClient, swpos );
xRatio := swpos.cx / xSize;
yRatio := swpos.cy / ySize;
// Calculate alignments for irregularly sized windows
RoundUpX := max( 1, Round(xRatio) );
While ( RoundUpX <> xRatio ) and (RoundUpX < xsize ) do
RoundUpX := RoundUpX * 10;
RoundUpY := max( 1, Round(yRatio) );
While ( RoundUpY <> yRatio ) and (RoundUpy < ysize ) do
RoundUpY := RoundUpY * 10;
with NewBlitter do
begin
ulStructLen := sizeof ( SETUP_BLITTER ) - 16;
fccSrcColorFormat := MyDive.fccColorFormat;
if coltranslate then
fccDstColorFormat := FourCC_Scrn
else
fccDstColorFormat := FOURCC_LUT8;
ulDitherType := 0;
fInvert := False;
// Calculate source rectangle based on fChangedRect
with fChangedRect do
begin
// X Source and width
ulSrcPosX := xLeft;
ulSrcWidth := succ(xRight - xLeft);
// Align source to avoid DIVE hiccups
if ulSrcPosX mod RoundUpX <> 0 then // Round down
ulSrcPosX := max( 0, (ulSrcPosX div RoundUpX) * RoundUpX );
if ulSrcWidth mod RoundUpX <> 0 then // Round up
ulSrcWidth := succ( ulSrcWidth div RoundUpX ) * RoundUpX;
// Limit source width to window width
ulSrcWidth := min( xSize - ulSrcPosX, ulSrcWidth );
// Y Source
ulSrcPosY := yBottom;
// Align source to avoid DIVE hiccups
if ulSrcPosY mod RoundUpY <> 0 then // Round up
begin
ulSrcPosY := max( 0, pred(ulSrcPosY div RoundUpY) * RoundUpY );
yBottom := ulSrcPosY;
end;
// Y Height
ulSrcHeight := succ(yTop - yBottom);
if ulSrcHeight mod RoundUpY <> 0 then // Round up
while (yTop<=ySize) and (ulSrcHeight+ulSrcPosY<ysize) and (ulSrcHeight mod RoundUpY <> 0) do
begin
Inc(yTop);
Inc(ulSrcHeight);
end;
ulSrcHeight := min( ysize - ulSrcPosY, ulSrcHeight );
// Destination rectangle, already aligned
lDstPosX := Round(xRatio*ulSrcPosX);
lDstPosY := swpos.cy-Round(yRatio*succ(yTop));
ulDstWidth := Round(xratio*ulSrcWidth);
ulDstHeight := Round(yratio*ulSrcHeight);
end; // With fChangedRect
end; // With
{$IFDEF DEBUG}
with NewBlitter do
log( Format('Blitting Src (%3d,%3d) (%3d,%3d) Dst (%3d,%3d) (%3d,%3d)',
[ ulSrcPosx, ulSrcPosY, ulSrcWidth, ulSrcHeight,
lDstPosx, lDstPosY, ulDstWidth, ulDstHeight] ) );
With fChangedRect do
log( Format(' - swpos (%3d,%3d) fchanged (%3d,%3d,%3d,%3d)',
[ swpos.cx, swpos.cy, xLeft, yBottom, xRight, yTop ] ) );
{$ENDIF}
if DiveSetupBlitter ( hDive, @NewBlitter ) <> 0 then ;
end; // FastBlit
with fChangedRect do
begin
xLeft := xsize;
xRight := 0;
yTop := 0;
yBottom := ySize;
end;
fChanged := False;
mtx_Rect.Release;
if DiveBlitImage ( hDive, fImage, dive_Buffer_Screen ) <> 0 then ;
mtx_Update.Release;
end
else
begin
mtx_Rect.Release;
// Nothing to do - wait for timer
rc := DosWaitEventSem( TimerEvent, 200 );
if rc = 6 then exit;
DosResetEventSem(TimerEvent,postcount);
end;
end;
end;
except
on e:exception do
raise EDive.Create( 'Blitter error '+e.message );
end;
end;
function tDiveWindow.BeginUpdate: Integer;
var
ulScanLineBytes:ULONG;
ulScanLines:ULONG;
begin
mtx_Update.Request;
Result := DiveBeginImageBufferAccess ( // <> 0 = error
hDive,
fImage,
Pointer( fDisplayBuf ),
ulScanLineBytes,
ulScanLines );
if Result <> 0 then
if Result = Dive_Err_No_Direct_Access then
raise EDive.Create( 'Display or graphics driver does not support direct video access' )
else
raise EDive.CreateFmt( 'Cannot access image buffer; rc = %d', [Result] );
end;
procedure tDiveWindow.EndUpdate;
begin
DiveEndImageBufferAccess ( hDive, fImage );
mtx_Update.Release;
end;
function PaletteThread( P: Pointer ): Longint;
var
MyDive : tDiveWindow;
i,j : Integer;
begin
MyDive := tDiveWindow( P );
With MyDive do
While not Stopping do
begin
If pChanged then
While pChanged do
begin
mtx_Palette.Request;
i := 0;
While not (i in PaletteChanged) do
Inc(i);
j := succ(i);
While (j in PaletteChanged) do
Inc(j);
PaletteChanged := PaletteChanged - [i..j-1];
mtx_Palette.Release;
DiveSetSourcePalette ( hDive,
i,
j-i,
@(p_rgbxpal8(pPalette)^[i]) );
pChanged := PaletteChanged <> [];
DosSleep(0);
end
else
DosSleep( 50 );
end;
end;
procedure tDiveWindow.SetRGBColor( Num: Word; red,green,blue: byte );
var
col: Longint;
begin
mtx_Palette.Request;
with p_rgbxpal8(pPalette)^[ Num ] do
begin
r := red;
g := green;
b := blue;
end;
PaletteChanged := PaletteChanged + [Num];
pChanged := True;
ImageChanged := True;
AllChanged;
mtx_Palette.Release;
end;
constructor tDiveWindow.Create( SizeX, SizeY: Longint; ColorBits: Byte );
begin
CreateRes( SizeX, SizeY, ColorBits, 0, 0 );
end;
Procedure tDiveWindow.SetPaletteArray;
const
EGAColors: array[0..15] of t_rgbx =
( {NAME COLOR}
(b:$00; g:$00; r:$00; x:pc_Reserved ),{Black EGA 0}
(b:$FC; g:$00; r:$00; x:pc_Reserved ),{Blue EGA 1}
(b:$24; g:$FC; r:$24; x:pc_Reserved ),{Green EGA 2}
(b:$FC; g:$FC; r:$00; x:pc_Reserved ),{Cyan EGA 3}
(b:$14; g:$14; r:$FC; x:pc_Reserved ),{Red EGA 4}
(b:$FC; g:$00; r:$B0; x:pc_Reserved ),{Magenta EGA 5}
(b:$00; g:$48; r:$70; x:pc_Reserved ),{Brown EGA 20}
(b:$C4; g:$C4; r:$C4; x:pc_Reserved ),{White EGA 7}
// (b:$34; g:$34; r:$34; x:pc_Reserved ),{Gray EGA 56}
// (b:$70; g:$00; r:$00; x:pc_Reserved ),{Lt Blue EGA 57}
(b:$54; g:$54; r:$54; x:pc_Reserved ),{Gray EGA 56}
(b:$A0; g:$00; r:$00; x:pc_Reserved ),{Lt Blue EGA 57}
(b:$00; g:$70; r:$00; x:pc_Reserved ),{Lt Green EGA 58}
(b:$70; g:$70; r:$00; x:pc_Reserved ),{Lt Cyan EGA 59}
(b:$00; g:$00; r:$70; x:pc_Reserved ),{Lt Red EGA 60}
(b:$70; g:$00; r:$70; x:pc_Reserved ),{Lt Magenta EGA 61}
(b:$24; g:$FC; r:$FC; x:pc_Reserved ),{Yellow EGA 62}
(b:$FC; g:$FC; r:$FC; x:pc_Reserved ) {Br. White EGA 63}
);
const
start = 0;
var
i,j:longint;
rgbxpal:p_rgbxpal8;
begin
GetMem(pPalette,256*sizeof(ULONG));
rgbxpal:=pPalette;
FillChar(rgbxpal^,sizeof(rgbxpal^),#0);
for i:=0 to 255 do
rgbxpal^[i] := EGAColors[i mod 16];
for i:=16+Start to 31+Start do
with rgbxpal^[i] do
begin
r := (i-15-Start)*16-1;
g := (i-15-Start)*16-1;
b := (i-15-Start)*16-1;
x := pc_Reserved;
end;
for i:=32+Start to 47+Start do
with rgbxpal^[i] do
begin
j := 15+i-32-Start;
if j <= 7 then
b := (7-j)*16
else
b := 0;
if j <= 7 then
g := 0
else
g := (j-15)*16;
if j <= 15 then
r := (j-15)*16
else
r := (31-j)*16;
x := pc_Reserved;
end;
end;
constructor tDiveWindow.CreateRes( SizeX, SizeY: Longint; ColorBits: Byte; ResType, ResID: Longint );
var
NullPtr: Pointer;
ScanLineBytes: Longint;
ScanLines: Longint;
Buffer: Pointer;
h_mq : HMq;
rc: Bool;
begin
If not (ColorBits in [8,16,24]) then
Raise EDive.Create( 'Only colour depths of 8, 16 or 24 is allowed' );
fColorBits := ColorBits;
NullPtr := nil;
if DiveOpen ( hDive, FALSE, NullPtr ) <> 0 then
Raise EDive.Create( 'Cannot open DIVE engine' );
fSizeX := SizeX;
fSizeY := SizeY;
fLineSize := 0;
Case ColorBits of
8 : FccColorFormat := FourCC_LUT8;
16 : FccColorFormat := FourCC_R565;
24 : FccColorFormat := FourCC_BGR4;
end;
if DiveAllocImageBuffer( hDive, // Dive Handle
fImage, // Image handle number
fccColorFormat, // Color depth
fSizeX, // X size
fSizeY, // Y size
fLineSize,
nil ) <> 0 then
Raise EDive.Create( 'Failed to allocate DIVE image buffer' );
if DiveBeginImageBufferAccess( hDive, // Dive Handle
fImage,
Buffer,
ScanLineBytes,
ScanLines ) <> 0 then
begin
DiveFreeImageBuffer( hDive, fImage );
Raise EDive.Create( 'Failed to access DIVE image buffer' );
end;
Fillchar( Buffer^, fSizeX*fSizeY, 0 );
DiveEndImageBufferAccess ( hDive, fImage );
SetPaletteArray; // Set up default palette
ScreenX := WinQuerySysValue ( HWND_DESKTOP, SV_CXSCREEN );
ScreenY := WinQuerySysValue ( HWND_DESKTOP, SV_CYSCREEN );
h_ab := WinInitialize ( 0 );
h_mq := WinCreateMsgQueue ( h_ab, 0 );
InitWindow( ResType, ResId );
rc := WinSetWindowULong( hwndClient, 0, Longint(Self) );
if rc then
WinSetVisibleRegionNotify ( hwndClient, TRUE );
if rc then
rc := WinPostMsg ( hwndFrame, WM_VRNENABLED, 0, 0 );
if not rc then
Raise EDive.CreateFmt( 'Error initialising frame window; rc = %d', [rc] );
Stopping := False;
LineMode := False;
PauseDisplay := False;
UpdateBuffer := nil;
MessageHandler := nil;
pChanged := False;
PaletteChanged := [];
fChanged := True;
Linethickness := 1;
LinePattern := $FFFFFFFF;
FillColor := 15;
FillBkColor := 0;
With fVP do
begin
x1 := 0; y1 := 0;
x2 := xsize-1; y2 := ysize-1;
end;
VPClip := True;
FastBlit := FastBlitSupported;
mtx_Update := tMutexSem.Create;
mtx_Rect := tMutexSem.Create;
mtx_Palette := tMutexSem.Create;
DosCreateEventSem( nil, TimerEvent, 0, False );
AllChanged;
// Blitter thread
tidBlitThread := VPBeginThread ( BlitterThread, 4*16384, Self );
DosSetPriority ( prtys_Thread, prtyc_Regular, 10, tidBlitThread );
// Palette thread
tidPaletteThread := VPBeginThread ( PaletteThread, 4*16384, Self );
DosSetPriority ( prtys_Thread, prtyc_IdleTime, 0, tidPaletteThread );
// Timer thread
tidTimerThread := VPBeginThread ( TimerThread, 16384, Self );
DosSetPriority ( prtys_Thread, prtyc_TimeCritical, 0, tidTimerThread );
end; // Create
procedure tDiveWindow.InitWindow( ResType, ResID: Longint );
var
flCreate: Longint;
WinPosX : Longint;
WinPosY : Longint;
begin
WinRegisterClass ( h_ab, pszMyWindow, MyWindowProc, 0, sizeof(ULONG) );
flCreate := FCF_TASKLIST or FCF_SYSMENU or FCF_TITLEBAR or
FCF_SIZEBORDER or FCF_MINMAX or FCF_SCREENALIGN
or ResType;
hwndFrame := WinCreateStdWindow ( HWND_DESKTOP,
WS_VISIBLE, flCreate,
pszMyWindow,
nil, // pszTitleText,
WS_SYNCPAINT or WS_VISIBLE,
0,
ResId,
@hwndClient);
if hwndFrame = 0 then
Raise EDive.Create( 'Failed to create frame window' );
WinPosX := ScreenX div 2 - ( GetSnapWidth(fSizeX) div 2 );
WinPosY := ScreenY div 2 - ( GetSnapHeight(fSizeY) div 2 );
WinSetWindowPos ( hwndFrame, HWND_TOP,
WinPosX, WinPosY,
GetSnapWidth( fSizeX ),
GetSnapHeight( fSizeY ),
SWP_MOVE or SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
end; // InitWindow
function tDiveWindow.GetColours: Longint;
begin
GetColours := 1 shl fColorBits;
end;
destructor tDiveWindow.Destroy;
begin
Stopping := True;
DosWaitThread ( tidBlitThread, DCWW_WAIT );
WinSetVisibleRegionNotify ( hwndClient, FALSE );
DiveFreeImageBuffer( hDive, fImage );
DiveClose( hDive );
WinDestroyWindow ( hwndFrame );
FreeMem(pPalette,256*sizeof(ULONG));
end; // Destroy
procedure tDiveWindow.Run;
var
q_msg : QMSG;
begin
while WinGetMsg ( h_ab, q_msg, 0, 0, 0 ) do
WinDispatchMsg ( h_ab, q_msg );
end;
// Transform native x,y to coordinates within ViewPort.
// Returns TRUE, if coordinates are displayable.
function tDiveWindow.VPTransformXY( var x, y: Integer ): Boolean;
begin
with ViewPort do
begin
inc( x, x1 );
inc( y, y1 );
Result := ( ( x >= 0 ) and ( x < xSize ) and
( y >= 0 ) and ( y < ySize ) ) and
( not VPClip or
( ( x >= x1 ) and ( x <= x2 ) and
( y >= y1 ) and ( y <= y2 ) ) );
end;
end;
// Transform native (x1,y) and (x2,y) to coordinates within ViewPort.
procedure tDiveWindow.VPTransformXXY( var xa, xb, y: Integer );
begin
with ViewPort do
begin
inc( xa, x1 );
inc( xb, x1 );
inc( y, y1 );
end;
end;
// Transform native (x1,y) and (x2,y) to coordinates within ViewPort.
procedure tDiveWindow.VPTransformXYXY( var xa, ya, xb, yb: Integer );
begin
with ViewPort do
begin
inc( xa, x1 );
inc( xb, x1 );
inc( ya, y1 );
inc( yb, y1 );
end;
end;
// Return buffer address based on native coordinates
function tDiveWindow.VPBufAdr( x,y: Integer ): Integer;
begin
With ViewPort do
Result := x+x1+(y+y1)*xSize;
end;
// Takes x,y within VP
function tDiveWindow.GetPix(x,y: Longint): Longint;
begin
if VPTransformXY( x, y ) then
Result := DisplayBuffer^[ x+y*xSize ]
else
Result := -1;
end;
// Takes x,y within VP
procedure tDiveWindow.SetPix(x,y: Longint; Value: Longint);
var
BufOfs: Integer;
begin
If VPTransformXY( x, y ) then
begin
BufOfs := x+y*xSize;
case LinePutMode of
0: DisplayBuffer^[ BufOfs ] := Value;
1: DisplayBuffer^[ BufOfs ] := DisplayBuffer^[ BufOfs ] xor Value;
2: DisplayBuffer^[ BufOfs ] := DisplayBuffer^[ BufOfs ] or Value;
3: DisplayBuffer^[ BufOfs ] := DisplayBuffer^[ BufOfs ] and Value;
4: DisplayBuffer^[ BufOfs ] := not Value;
end;
PixelChanged( x, y );
end;
end;
// Takes x,y in world coordinates
function tDiveWindow.GetWinPix(x,y: Longint): Longint;
begin
Result := DisplayBuffer^[ x+y*xSize ];
end;
// Takes x,y in world coordinates
procedure tDiveWindow.SetWinPix(x,y, Value: Longint );
var
Disp: ^Byte;
begin
With ViewPort do
if ( ( x >= 0 ) and ( x < xSize ) and
( y >= 0 ) and ( y < ySize ) ) and // Within screen
( ( ( x >= x1 ) and ( x <= x2 ) and
( y >= y1 ) and ( y <= y2 ) ) or // Within Clip
not VPClip ) then // Not clipped
begin
Disp := Ptr( longint(DisplayBuffer) + x+y*xSize );
if not odd(LinePattern shr (PatternInx mod 32)) then
Value := 0;
case LinePutMode of
0: Disp^ := Value;
1: Disp^ := Disp^ xor Value;
2: Disp^ := Disp^ or Value;
3: Disp^ := Disp^ and Value;
4: Disp^ := Disp^ and not Value;
end;
inc( PatternInx );
end;
end;
{$Frame-} {$Uses none}
procedure SwapLong( var a,b: Longint );
asm
mov eax,a
mov edx,b
mov ecx,[eax] // Value of a
xchg ecx,[edx] // Swap with value of b
mov [eax],ecx
end;
{$Frame-} {$Uses none}
procedure SwapQW( var a,b );
asm
mov eax,a
mov edx,b
mov ecx,[eax] // Value of a
xchg ecx,[edx] // Swap with value of b
mov [eax],ecx
add eax,4 // High dwords
add edx,4
mov ecx,[eax]
xchg ecx,[edx]
mov [eax],ecx
end;
procedure Swap( var a,b; size: Longint );
var
temp : array[1..100] of byte; { Max size to swap }
begin
move( a, temp, size );
move( b, a, size );
move( temp, a, size );
end;
type
fix = record case boolean of (* 32Bit Fixed-Point number *)
true:(fix:longint);
false:(f:SmallWord;i:SmallInt);
end;
// Coordinates within viewport passed
procedure tDiveWindow.DrawFillLine( x1,x2,y: Integer );
const
mask_3 : ARRAY [0..15] OF WORD= ($8000,$4000,$2000,$1000,$800,$400,$200,
$100,$80,$40,$20,$10,$8,$4,$2,$1);
var
i: integer;
BufInx: Integer;
begin
VPTransformXXY( x1, x2, y );
if x1 > x2 then SwapLong( x1, x2 );
if y < 0 then exit;
If VPClip then
begin
// Clip to viewport
x1 := max( x1, ViewPort.x1 );
x2 := min( x2, VPXMax );
if ( y > ViewPort.y2 ) or ( y < ViewPort.y1 ) then
exit;
end
else
begin
x1 := max( 0, x1 );
x2 := min( VPWidth, x2 );
if y > ySize then
exit;
end;
BufInx := x1+y*xSize;
for i := x1 to x2 do
begin
if ( FillPattern[y AND 15] and mask_3[i and 15] )<> 0 then
DisplayBuffer^[BufInx] := FillColor
else
DisplayBuffer^[BufInx] := FillBkColor;
Inc( BufInx );
end;
end;
function tDiveWindow.FillPatternColor( x, y: Integer ): Integer;
const
mask_3 : ARRAY [0..15] OF WORD= ($8000,$4000,$2000,$1000,$800,$400,$200,
$100,$80,$40,$20,$10,$8,$4,$2,$1);
var
Dummy: Integer;
begin
VPTransformXXY( x, Dummy, y );
if y < 0 then exit;
If VPClip then
begin
// Clip to viewport
x := max( x, ViewPort.x1 );
if ( y > ViewPort.y2 ) or ( y < ViewPort.y1 ) then
exit;
end
else
begin
x := max( 0, x );
if y > ySize then
exit;
end;
if ( FillPattern[y AND 15] and mask_3[x and 15] ) <> 0 then
Result := FillColor
else
Result := FillBkColor;
end;
// Optimised horizontal line routine for xxxPut modes
procedure tDiveWindow.FillLine( x1,x2,y,c: Longint );
var
Disp: ^Byte;
i: Integer;
col: Integer;
begin
Disp := Ptr( Longint(DisplayBuffer) + x1+y*xSize );
case LinePutMode of
10: // NormalPut
for i := x1 to x2 do
begin
if odd(LinePattern shr ((i+y) mod 32)) then
col := c
else
col := 0;
Disp^ := col;
Inc( Disp );
end;
1 : // XorPut
for i := x1 to x2 do
begin
if odd(LinePattern shr ((i+y) mod 32)) then
col := c
else
col := 0;
Disp^ := Disp^ xor col;
Inc( Disp );
end;
2 : // OrPut
for i := x1 to x2 do
begin
if odd(LinePattern shr ((i+y) mod 32)) then
col := c
else
col := 0;
Disp^ := Disp^ or col;
Inc( Disp );
end;
3 : // AndPut
for i := x1 to x2 do
begin
if odd(LinePattern shr ((i+y) mod 32)) then
col := c
else
col := 0;
Disp^ := Disp^ and col;
Inc( Disp );
end;
4 : // NotPut
for i := x1 to x2 do
begin
if odd(LinePattern shr ((i+y) mod 32)) then
col := c
else
col := 0;
Disp^ := Disp^ and not col;
Inc( Disp );
end;
end;
end;
// Coordinates within viewport passed
procedure tDiveWindow.DrawLine( x1,y1, x2,y2, c: Longint );
var
dyDdx,dxDdy,sy,sx:fix;
dy,dx,h: integer;
s: String;
i, it: integer;
x,y: Integer;
ltd2 : Integer;
xa,ya: Integer;
procedure ThickLineX( x,y: Integer);
begin
if LineThickness = 3 then
begin
Dec( PatternInx );
SetWinPix( pred(x), y, c );
Dec( PatternInx );
SetWinPix( succ(x), y, c );
end;
end;
procedure ThickLineY( x,y: Integer );
begin
if LineThickness = 3 then
begin
Dec( PatternInx );
SetWinPix( x, pred(y), c );
Dec( PatternInx );
SetWinPix( x, succ(y), c );
end;
end;
begin
dY := Abs( y2-y1 );
dX := Abs( x2-x1 );
// Transform to global coordinates
VPTransformXYXY( x1, y1, x2, y2 );
ltd2 := Linethickness div 2;
if dY = 0 then
begin // Horizontal line
if x2 < x1 then
SwapLong( x1, x2 );
If VPClip then
begin
// Clip to viewport
x1 := max( x1, ViewPort.x1 );
x2 := min( x2, VPXMax );
if y2-ltd2 > ViewPort.y2 then
exit;
if y1+ltd2 < 0 then
exit;
y1 := max( ViewPort.y1, min( y1+ltd2, ViewPort.y2-ltd2 ) );
end
else
begin
x1 := max( 0, x1 );
x2 := min( xSize-1, x2 );
if y2-ltd2 > ysize-1 then
exit;
if y1+ltd2 < 0 then
exit;
y1 := min( y1+ltd2, ySize-1-ltd2 );
end;
x1 := min( x1, x2 );
for it := -ltd2 to ltd2 do
if ( LinePutMode = 0 ) and ( LinePattern = $FFFFFFFF ) then
Fillchar( DisplayBuffer^[(y1+it)*xSize+x1], x2-x1+1, c)
else
// Apply linestyle and put-mode (xor, or, etc) on line
FillLine( x1, x2, y1+it, c );
end
else
begin
if dX > dY then
begin
if x2 < x1 then
begin
SwapLong( x1, x2 );
SwapLong( y1, y2 );
end;
SetWinPix( x1, y1, c );
ThickLineY( x1, y1 );
if dX <> 0 then
begin
sy.i := y1;
sy.f := $8000;
dyDdx.i := y2-y1;
dyDdx.f := 0;
dyDdx.fix := dyDdx.fix div dX;
x := x1;
while x < x2-1 do
begin
inc( x );
inc( sy.fix, dyDdx.fix );
SetWinPix( x, sy.i, c );
ThickLineY( x, sy.i );
end;
end;
SetWinPix( x2, y2, c );
ThickLineY( x2, y2 );
end // dX > dY
else
begin
if y2 < y1 then
begin
SwapLong( x1, x2 );
SwapLong( y1, y2 );
end;
SetWinPix( x1, y1, c );
ThickLineX( x1, y1 );
if dY <> 0 then
begin
sx.i:= x1;
sx.f:= $8000;
dxDdy.i := x2-x1;
dxDdy.f := 0;
dxDdy.fix := dxDdy.fix div dY;
y := y1;
while y < y2-1 do
begin
Inc( y );
Inc( sx.fix, dxDdy.fix );
SetWinPix( sx.i, y, c );
ThickLineX( sx.i, y );
end;
end;
SetWinPix( x2, y2, c );
ThickLineX( x2, y2 );
end; // dY > dX
end; // dY <> 0
RectChanged( x1-ltd2,y1-ltd2, x2+ltd2,y2+ltd2 );
end; // DrawLine
procedure tDiveWindow.DrawFillRect( x1,y1, x2,y2, c: Longint );
var
y: Integer;
begin
if (x1 > x2) then SwapLong( x1, x2 );
if (y1 > y2) then SwapLong( y1, y2 );
for y := y1 to y2 do
DrawFillLine( x1, x2, y );
DrawBox( x1,y1, x2,y2, c );
end;
procedure tDiveWindow.DrawBox( x1,y1, x2,y2, c: Longint );
var
p1, p2, p3, p4 : Pixel;
begin
p1.x := x1; p1.y := y1;
p2.x := x2; p2.y := y2;
p3.x := x1; p3.y := y2;
p4.x := x2; p4.y := y1;
DrawQuad( p1, p2, p3, p4, c );
end; // Drawbox
procedure tDiveWindow.DrawTriangle(p1,p2,p3:pixel;c:integer);
var x21,x31,x32,
y21,y31,y32:integer;
ex,
e1x,
edx,
e1dx:fix;
N: longint;
begin
if LineMode then
begin
DrawLine( p1.x, p1.y, p2.x, p2.y, c); // Only edges
DrawLine( p2.x, p2.y, p3.x, p3.y, c);
DrawLine( p3.x, p3.y, p1.x, p1.y, c);
end
else
begin
// Make sure p1y <= p2y <= p3y
if p1.y > p2.y then SwapQW( p1, p2 );
if p1.y > p3.y then SwapQW( p1, p3 );
if p2.y > p3.y then SwapQW( p2, p3 );
y31 := p3.y - p1.y; // Length of longest edge
if y31 <> 0 then
begin // No horizontal line?
y21 := p2.y - p1.y; // Short edges
x21 := p2.x - p1.x;
x31 := p3.x - p1.x;
N := y21*x31 - y31*x21;
SetPix( p1.x, p1.y, c ); // Uppermost pixel
Inc( p1.y );
ex.i := p1.x; ex.f := $8000; // Start value for x
edx.i := x31; edx.f := 0;
edx.fix := edx.fix div y31;
if y21 <> 0 then
begin // p1-p2 not horizontal
e1x.fix := ex.fix;
e1dx.i := x21; e1dx.f := 0;
e1dx.fix := e1dx.fix div y21;
while p1.y < p2.y do
begin // All lines between p1y and p2y
Inc( ex.fix,edx.fix);
Inc( e1x.fix,e1dx.fix);
DrawLine( ex.i, p1.y, e1x.i, p1.y, c);
Inc( p1.y );
end;
Inc( ex.fix, edx.fix );
end; // y21 <> 0
p1.y := p2.y;
SetPix( ex.i, p1.y, c );
SetPix( p2.x, p2.y, c );
DrawLine( ex.i, p1.y, p2.x, p1.y, c );
Inc( p1.y );
y32 := p3.y - p2.y;
if y32 <> 0 then
begin
x32 := p3.x - p2.x;
e1x.i := p2.x; e1x.f := $8000;
e1dx.i := x32; e1dx.f := 0;
e1dx.fix := e1dx.fix div y32;
while p1.y < p3.y do
begin
Inc( ex.fix, edx.fix );
Inc( e1x.fix, e1dx.fix );
DrawLine( ex.i, p1.y, e1x.i, p1.y, c );
Inc(p1.y);
end;
end; // y32 <> 0
SetPix( p3.x, p3.y, c );
end // y31 <> 0
else
DrawLine( p1.x, p1.y, p3.x, p3.y, c );
end; // Not linemode
end; // DrawTriangle
procedure tDiveWindow.DrawQuad( p1,p2,p3,p4: Pixel; c: Longint );
var
l1,l2,l1dx,l2dx:fix;
under1,under2:boolean;
Procedure AssignLine(var p1,p2:pixel;var l,ldx:fix);
var
dX,dY: Integer;
begin
dX := p2.x-p1.x;
dY := p2.y-p1.y;
l.i := p1.x;
l.f := $8000;
ldx.i := dX;
ldx.f := 0;
ldx.fix := ldx.fix div dY;
end;
Procedure FillBetweenLines(y,ymax:integer);
begin
while y<=ymax do
begin
inc( l1.fix, l1dx.fix );
inc( l2.fix, l2dx.fix );
DrawLine( l1.i,y, l2.i,y, c );
Inc( y );
end;
end;
begin
// Make sure that p1y<=p2y<=p3y<=p4y
if p1.y > p2.y then SwapQW( p1, p2 );
if p1.y > p3.y then SwapQW( p1, p3 );
if p1.y > p4.y then SwapQW( p1, p4 );
if p2.y > p3.y then SwapQW( p2, p3 );
if p2.y > p4.y then SwapQW( p2, p4 );
if p3.y > p4.y then SwapQW( p3, p4 );
if p4.y <> p1.y then
begin
if p3.y <> p1.y then
begin
if p1.x = p3.x then
begin
under1 := p2.x < p1.x;
under2 := p4.x < p1.x;
end
else
begin
under1:=p3.y-p2.y<(longint(p3.x-p2.x)*(p3.y-p1.y)) div (p3.x-p1.x);
under2:=p3.y-p4.y<(longint(p3.x-p4.x)*(p3.y-p1.y)) div (p3.x-p1.x);
end;
SetPix( p1.x, p1.y, c );
if under1 xor under2 then
begin
if LineMode then
begin
DrawLine( p1.x, p1.y, p2.x, p2.y, c );
DrawLine( p2.x, p2.y, p3.x, p3.y, c );
DrawLine( p3.x, p3.y, p4.x, p4.y, c );
DrawLine( p4.x, p4.y, p1.x, p1.y, c );
end
else
begin
AssignLine( p1, p4, l1, l1dx );
if p1.y = p2.y then
DrawLine( p1.x, p1.y, p2.x, p1.y, c)
else
begin
AssignLine( p1, p2, l2, l2dx );
FillBetweenLines( p1.y+1, p2.y );
end;
if p2.y <> p3.y then
begin
AssignLine( p2, p3, l2, l2dx );
FillBetweenLines( p2.y+1, p3.y );
end;
if p3.y <> p4.y then
begin
AssignLine( p3, p4, l2, l2dx );
FillBetweenLines( p3.y+1, p4.y );
end;
end;
end
else
begin
if LineMode then
begin
DrawLine( p1.x, p1.y, p2.x, p2.y, c );
DrawLine( p2.x, p2.y, p4.x, p4.y, c );
DrawLine( p4.x, p4.y, p3.x, p3.y, c );
DrawLine( p3.x, p3.y, p1.x, p1.y, c );
end
else
begin
AssignLine(p1,p3,l1,l1dx);
if p1.y = p2.y then
DrawLine( p1.x, p1.y, p2.x, p1.y, c)
else
begin
AssignLine( p1, p2, l2, l2dx );
FillBetweenLines( p1.y+1, p2.y );
end;
if p2.y <> p4.y then
begin
AssignLine( p2, p4, l2, l2dx );
if p2.y <> p3.y then
FillBetweenLines( p2.y+1, p3.y );
if p3.y <> p4.y then
begin
AssignLine( p3, p4, l1, l1dx );
FillBetweenLines( p3.y+1, p4.y );
end;
end;
end;
end;
end
else
begin
DrawLine( p1.x, p1.y, p2.x, p1.y, c );
DrawLine( p1.x, p1.y, p3.x, p1.y, c );
AssignLine( p2, p4, l1, l1dx );
AssignLine( p3, p4, l2, l2dx );
FillBetweenLines( p3.y+1, p4.y );
end;
end
else
begin
DrawLine(p1.x, p1.y, p2.x, p1.y, c);
DrawLine(p1.x, p1.y, p3.x, p1.y, c);
DrawLine(p1.x, p1.y, p4.x, p1.y, c);
end;
end; // DrawQuad
const
Font8x8:array[0..$7FF] of byte = (
$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$7E ,$81 ,$A5 ,$81 ,$BD ,$99 ,$81 ,$7E
,$7E ,$FF ,$DB ,$FF ,$C3 ,$E7 ,$FF ,$7E ,$6C ,$FE ,$FE ,$FE ,$7C ,$38 ,$10 ,$00
,$10 ,$38 ,$7C ,$FE ,$7C ,$38 ,$10 ,$00 ,$38 ,$7C ,$38 ,$FE ,$FE ,$7C ,$38 ,$7C
,$10 ,$10 ,$38 ,$7C ,$FE ,$7C ,$38 ,$7C ,$00 ,$00 ,$18 ,$3C ,$3C ,$18 ,$00 ,$00
,$FF ,$FF ,$E7 ,$C3 ,$C3 ,$E7 ,$FF ,$FF ,$00 ,$3C ,$66 ,$42 ,$42 ,$66 ,$3C ,$00
,$FF ,$C3 ,$99 ,$BD ,$BD ,$99 ,$C3 ,$FF ,$0F ,$07 ,$0F ,$7D ,$CC ,$CC ,$CC ,$78
,$3C ,$66 ,$66 ,$66 ,$3C ,$18 ,$7E ,$18 ,$3F ,$33 ,$3F ,$30 ,$30 ,$70 ,$F0 ,$E0
,$7F ,$63 ,$7F ,$63 ,$63 ,$67 ,$E6 ,$C0 ,$99 ,$5A ,$3C ,$E7 ,$E7 ,$3C ,$5A ,$99
,$80 ,$E0 ,$F8 ,$FE ,$F8 ,$E0 ,$80 ,$00 ,$02 ,$0E ,$3E ,$FE ,$3E ,$0E ,$02 ,$00
,$18 ,$3C ,$7E ,$18 ,$18 ,$7E ,$3C ,$18 ,$66 ,$66 ,$66 ,$66 ,$66 ,$00 ,$66 ,$00
,$7F ,$DB ,$DB ,$7B ,$1B ,$1B ,$1B ,$00 ,$3E ,$63 ,$38 ,$6C ,$6C ,$38 ,$CC ,$78
,$00 ,$00 ,$00 ,$00 ,$7E ,$7E ,$7E ,$00 ,$18 ,$3C ,$7E ,$18 ,$7E ,$3C ,$18 ,$FF
,$18 ,$3C ,$7E ,$18 ,$18 ,$18 ,$18 ,$00 ,$18 ,$18 ,$18 ,$18 ,$7E ,$3C ,$18 ,$00
,$00 ,$18 ,$0C ,$FE ,$0C ,$18 ,$00 ,$00 ,$00 ,$30 ,$60 ,$FE ,$60 ,$30 ,$00 ,$00
,$00 ,$00 ,$C0 ,$C0 ,$C0 ,$FE ,$00 ,$00 ,$00 ,$24 ,$66 ,$FF ,$66 ,$24 ,$00 ,$00
,$00 ,$18 ,$3C ,$7E ,$FF ,$FF ,$00 ,$00 ,$00 ,$FF ,$FF ,$7E ,$3C ,$18 ,$00 ,$00
,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$30 ,$78 ,$78 ,$78 ,$30 ,$00 ,$30 ,$00
,$6C ,$6C ,$6C ,$00 ,$00 ,$00 ,$00 ,$00 ,$6C ,$6C ,$FE ,$6C ,$FE ,$6C ,$6C ,$00
,$30 ,$7C ,$C0 ,$78 ,$0C ,$F8 ,$30 ,$00 ,$00 ,$C6 ,$CC ,$18 ,$30 ,$66 ,$C6 ,$00
,$38 ,$6C ,$38 ,$76 ,$DC ,$CC ,$76 ,$00 ,$60 ,$60 ,$C0 ,$00 ,$00 ,$00 ,$00 ,$00
,$18 ,$30 ,$60 ,$60 ,$60 ,$30 ,$18 ,$00 ,$60 ,$30 ,$18 ,$18 ,$18 ,$30 ,$60 ,$00
,$00 ,$66 ,$3C ,$FF ,$3C ,$66 ,$00 ,$00 ,$00 ,$30 ,$30 ,$FC ,$30 ,$30 ,$00 ,$00
,$00 ,$00 ,$00 ,$00 ,$00 ,$30 ,$30 ,$60 ,$00 ,$00 ,$00 ,$FC ,$00 ,$00 ,$00 ,$00
,$00 ,$00 ,$00 ,$00 ,$00 ,$30 ,$30 ,$00 ,$06 ,$0C ,$18 ,$30 ,$60 ,$C0 ,$80 ,$00
,$7C ,$C6 ,$CE ,$DE ,$F6 ,$E6 ,$7C ,$00 ,$30 ,$70 ,$30 ,$30 ,$30 ,$30 ,$FC ,$00
,$78 ,$CC ,$0C ,$38 ,$60 ,$CC ,$FC ,$00 ,$78 ,$CC ,$0C ,$38 ,$0C ,$CC ,$78 ,$00
,$1C ,$3C ,$6C ,$CC ,$FE ,$0C ,$1E ,$00 ,$FC ,$C0 ,$F8 ,$0C ,$0C ,$CC ,$78 ,$00
,$38 ,$60 ,$C0 ,$F8 ,$CC ,$CC ,$78 ,$00 ,$FC ,$CC ,$0C ,$18 ,$30 ,$30 ,$30 ,$00
,$78 ,$CC ,$CC ,$78 ,$CC ,$CC ,$78 ,$00 ,$78 ,$CC ,$CC ,$7C ,$0C ,$18 ,$70 ,$00
,$00 ,$30 ,$30 ,$00 ,$00 ,$30 ,$30 ,$00 ,$00 ,$30 ,$30 ,$00 ,$00 ,$30 ,$30 ,$60
,$18 ,$30 ,$60 ,$C0 ,$60 ,$30 ,$18 ,$00 ,$00 ,$00 ,$FC ,$00 ,$00 ,$FC ,$00 ,$00
,$60 ,$30 ,$18 ,$0C ,$18 ,$30 ,$60 ,$00 ,$78 ,$CC ,$0C ,$18 ,$30 ,$00 ,$30 ,$00
,$7C ,$C6 ,$DE ,$DE ,$DE ,$C0 ,$78 ,$00 ,$30 ,$78 ,$CC ,$CC ,$FC ,$CC ,$CC ,$00
,$FC ,$66 ,$66 ,$7C ,$66 ,$66 ,$FC ,$00 ,$3C ,$66 ,$C0 ,$C0 ,$C0 ,$66 ,$3C ,$00
,$F8 ,$6C ,$66 ,$66 ,$66 ,$6C ,$F8 ,$00 ,$7E ,$60 ,$60 ,$78 ,$60 ,$60 ,$7E ,$00
,$7E ,$60 ,$60 ,$78 ,$60 ,$60 ,$60 ,$00 ,$3C ,$66 ,$C0 ,$C0 ,$CE ,$66 ,$3E ,$00
,$CC ,$CC ,$CC ,$FC ,$CC ,$CC ,$CC ,$00 ,$78 ,$30 ,$30 ,$30 ,$30 ,$30 ,$78 ,$00
,$1E ,$0C ,$0C ,$0C ,$CC ,$CC ,$78 ,$00 ,$E6 ,$66 ,$6C ,$78 ,$6C ,$66 ,$E6 ,$00
,$60 ,$60 ,$60 ,$60 ,$60 ,$60 ,$7E ,$00 ,$C6 ,$EE ,$FE ,$FE ,$D6 ,$C6 ,$C6 ,$00
,$C6 ,$E6 ,$F6 ,$DE ,$CE ,$C6 ,$C6 ,$00 ,$38 ,$6C ,$C6 ,$C6 ,$C6 ,$6C ,$38 ,$00
,$FC ,$66 ,$66 ,$7C ,$60 ,$60 ,$F0 ,$00 ,$78 ,$CC ,$CC ,$CC ,$DC ,$78 ,$1C ,$00
,$FC ,$66 ,$66 ,$7C ,$6C ,$66 ,$E6 ,$00 ,$78 ,$CC ,$E0 ,$70 ,$1C ,$CC ,$78 ,$00
,$FC ,$30 ,$30 ,$30 ,$30 ,$30 ,$30 ,$00 ,$CC ,$CC ,$CC ,$CC ,$CC ,$CC ,$FC ,$00
,$CC ,$CC ,$CC ,$CC ,$CC ,$78 ,$30 ,$00 ,$C6 ,$C6 ,$C6 ,$D6 ,$FE ,$EE ,$C6 ,$00
,$C6 ,$C6 ,$6C ,$38 ,$38 ,$6C ,$C6 ,$00 ,$CC ,$CC ,$CC ,$78 ,$30 ,$30 ,$78 ,$00
,$FE ,$06 ,$0C ,$18 ,$30 ,$60 ,$FE ,$00 ,$78 ,$60 ,$60 ,$60 ,$60 ,$60 ,$78 ,$00
,$C0 ,$60 ,$30 ,$18 ,$0C ,$06 ,$02 ,$00 ,$78 ,$18 ,$18 ,$18 ,$18 ,$18 ,$78 ,$00
,$10 ,$38 ,$6C ,$C6 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$FF
,$30 ,$30 ,$18 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$78 ,$0C ,$7C ,$CC ,$76 ,$00
,$E0 ,$60 ,$60 ,$7C ,$66 ,$66 ,$DC ,$00 ,$00 ,$00 ,$78 ,$CC ,$C0 ,$CC ,$78 ,$00
,$1C ,$0C ,$0C ,$7C ,$CC ,$CC ,$76 ,$00 ,$00 ,$00 ,$78 ,$CC ,$FC ,$C0 ,$78 ,$00
,$38 ,$6C ,$60 ,$F0 ,$60 ,$60 ,$F0 ,$00 ,$00 ,$00 ,$76 ,$CC ,$CC ,$7C ,$0C ,$F8
,$E0 ,$60 ,$6C ,$76 ,$66 ,$66 ,$E6 ,$00 ,$30 ,$00 ,$70 ,$30 ,$30 ,$30 ,$78 ,$00
,$0C ,$00 ,$0C ,$0C ,$0C ,$CC ,$CC ,$78 ,$E0 ,$60 ,$66 ,$6C ,$78 ,$6C ,$E6 ,$00
,$70 ,$30 ,$30 ,$30 ,$30 ,$30 ,$78 ,$00 ,$00 ,$00 ,$CC ,$FE ,$FE ,$D6 ,$C6 ,$00
,$00 ,$00 ,$F8 ,$CC ,$CC ,$CC ,$CC ,$00 ,$00 ,$00 ,$78 ,$CC ,$CC ,$CC ,$78 ,$00
,$00 ,$00 ,$DC ,$66 ,$66 ,$7C ,$60 ,$F0 ,$00 ,$00 ,$76 ,$CC ,$CC ,$7C ,$0C ,$1E
,$00 ,$00 ,$DC ,$76 ,$66 ,$60 ,$F0 ,$00 ,$00 ,$00 ,$7C ,$C0 ,$78 ,$0C ,$F8 ,$00
,$10 ,$30 ,$7C ,$30 ,$30 ,$34 ,$18 ,$00 ,$00 ,$00 ,$CC ,$CC ,$CC ,$CC ,$76 ,$00
,$00 ,$00 ,$CC ,$CC ,$CC ,$78 ,$30 ,$00 ,$00 ,$00 ,$C6 ,$D6 ,$FE ,$FE ,$6C ,$00
,$00 ,$00 ,$C6 ,$6C ,$38 ,$6C ,$C6 ,$00 ,$00 ,$00 ,$CC ,$CC ,$CC ,$7C ,$0C ,$F8
,$00 ,$00 ,$FC ,$98 ,$30 ,$64 ,$FC ,$00 ,$1C ,$30 ,$30 ,$E0 ,$30 ,$30 ,$1C ,$00
,$18 ,$18 ,$18 ,$00 ,$18 ,$18 ,$18 ,$00 ,$E0 ,$30 ,$30 ,$1C ,$30 ,$30 ,$E0 ,$00
,$76 ,$DC ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$10 ,$38 ,$6C ,$C6 ,$C6 ,$FE ,$00
,$78 ,$CC ,$C0 ,$CC ,$78 ,$18 ,$0C ,$78 ,$00 ,$CC ,$00 ,$CC ,$CC ,$CC ,$7E ,$00
,$1C ,$00 ,$78 ,$CC ,$FC ,$C0 ,$78 ,$00 ,$7E ,$C3 ,$3C ,$06 ,$3E ,$66 ,$3F ,$00
,$CC ,$00 ,$78 ,$0C ,$7C ,$CC ,$7E ,$00 ,$E0 ,$00 ,$78 ,$0C ,$7C ,$CC ,$7E ,$00
,$30 ,$30 ,$78 ,$0C ,$7C ,$CC ,$7E ,$00 ,$00 ,$00 ,$78 ,$C0 ,$C0 ,$78 ,$0C ,$38
,$7E ,$C3 ,$3C ,$66 ,$7E ,$60 ,$3C ,$00 ,$CC ,$00 ,$78 ,$CC ,$FC ,$C0 ,$78 ,$00
,$E0 ,$00 ,$78 ,$CC ,$FC ,$C0 ,$78 ,$00 ,$CC ,$00 ,$70 ,$30 ,$30 ,$30 ,$78 ,$00
,$7C ,$C6 ,$38 ,$18 ,$18 ,$18 ,$3C ,$00 ,$E0 ,$00 ,$70 ,$30 ,$30 ,$30 ,$78 ,$00
,$C6 ,$38 ,$6C ,$C6 ,$FE ,$C6 ,$C6 ,$00 ,$30 ,$30 ,$00 ,$78 ,$CC ,$FC ,$CC ,$00
,$1C ,$00 ,$FC ,$60 ,$78 ,$60 ,$FC ,$00 ,$00 ,$00 ,$7F ,$0C ,$7F ,$CC ,$7F ,$00
,$3E ,$6C ,$CC ,$FE ,$CC ,$CC ,$CE ,$00 ,$78 ,$CC ,$00 ,$78 ,$CC ,$CC ,$78 ,$00
,$00 ,$CC ,$00 ,$78 ,$CC ,$CC ,$78 ,$00 ,$00 ,$E0 ,$00 ,$78 ,$CC ,$CC ,$78 ,$00
,$78 ,$CC ,$00 ,$CC ,$CC ,$CC ,$7E ,$00 ,$00 ,$E0 ,$00 ,$CC ,$CC ,$CC ,$7E ,$00
,$00 ,$CC ,$00 ,$CC ,$CC ,$7C ,$0C ,$F8 ,$C3 ,$18 ,$3C ,$66 ,$66 ,$3C ,$18 ,$00
,$CC ,$00 ,$CC ,$CC ,$CC ,$CC ,$78 ,$00 ,$18 ,$18 ,$7E ,$C0 ,$C0 ,$7E ,$18 ,$18
,$38 ,$6C ,$64 ,$F0 ,$60 ,$E6 ,$FC ,$00 ,$CC ,$CC ,$78 ,$FC ,$30 ,$FC ,$30 ,$30
,$F8 ,$CC ,$CC ,$FA ,$C6 ,$CF ,$C6 ,$C7 ,$0E ,$1B ,$18 ,$3C ,$18 ,$18 ,$D8 ,$70
,$1C ,$00 ,$78 ,$0C ,$7C ,$CC ,$7E ,$00 ,$38 ,$00 ,$70 ,$30 ,$30 ,$30 ,$78 ,$00
,$00 ,$1C ,$00 ,$78 ,$CC ,$CC ,$78 ,$00 ,$00 ,$1C ,$00 ,$CC ,$CC ,$CC ,$7E ,$00
,$00 ,$F8 ,$00 ,$F8 ,$CC ,$CC ,$CC ,$00 ,$FC ,$00 ,$CC ,$EC ,$FC ,$DC ,$CC ,$00
,$3C ,$6C ,$6C ,$3E ,$00 ,$7E ,$00 ,$00 ,$38 ,$6C ,$6C ,$38 ,$00 ,$7C ,$00 ,$00
,$30 ,$00 ,$30 ,$60 ,$C0 ,$CC ,$78 ,$00 ,$00 ,$00 ,$00 ,$FC ,$C0 ,$C0 ,$00 ,$00
,$00 ,$00 ,$00 ,$FC ,$0C ,$0C ,$00 ,$00 ,$C3 ,$C6 ,$CC ,$DE ,$33 ,$66 ,$CC ,$0F
,$C3 ,$C6 ,$CC ,$DB ,$37 ,$6F ,$CF ,$03 ,$18 ,$18 ,$00 ,$18 ,$18 ,$18 ,$18 ,$00
,$00 ,$33 ,$66 ,$CC ,$66 ,$33 ,$00 ,$00 ,$00 ,$CC ,$66 ,$33 ,$66 ,$CC ,$00 ,$00
,$22 ,$88 ,$22 ,$88 ,$22 ,$88 ,$22 ,$88 ,$55 ,$AA ,$55 ,$AA ,$55 ,$AA ,$55 ,$AA
,$DB ,$77 ,$DB ,$EE ,$DB ,$77 ,$DB ,$EE ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18
,$18 ,$18 ,$18 ,$18 ,$F8 ,$18 ,$18 ,$18 ,$18 ,$18 ,$F8 ,$18 ,$F8 ,$18 ,$18 ,$18
,$36 ,$36 ,$36 ,$36 ,$F6 ,$36 ,$36 ,$36 ,$00 ,$00 ,$00 ,$00 ,$FE ,$36 ,$36 ,$36
,$00 ,$00 ,$F8 ,$18 ,$F8 ,$18 ,$18 ,$18 ,$36 ,$36 ,$F6 ,$06 ,$F6 ,$36 ,$36 ,$36
,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$00 ,$00 ,$FE ,$06 ,$F6 ,$36 ,$36 ,$36
,$36 ,$36 ,$F6 ,$06 ,$FE ,$00 ,$00 ,$00 ,$36 ,$36 ,$36 ,$36 ,$FE ,$00 ,$00 ,$00
,$18 ,$18 ,$F8 ,$18 ,$F8 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$F8 ,$18 ,$18 ,$18
,$18 ,$18 ,$18 ,$18 ,$1F ,$00 ,$00 ,$00 ,$18 ,$18 ,$18 ,$18 ,$FF ,$00 ,$00 ,$00
,$00 ,$00 ,$00 ,$00 ,$FF ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$1F ,$18 ,$18 ,$18
,$00 ,$00 ,$00 ,$00 ,$FF ,$00 ,$00 ,$00 ,$18 ,$18 ,$18 ,$18 ,$FF ,$18 ,$18 ,$18
,$18 ,$18 ,$1F ,$18 ,$1F ,$18 ,$18 ,$18 ,$36 ,$36 ,$36 ,$36 ,$37 ,$36 ,$36 ,$36
,$36 ,$36 ,$37 ,$30 ,$3F ,$00 ,$00 ,$00 ,$00 ,$00 ,$3F ,$30 ,$37 ,$36 ,$36 ,$36
,$36 ,$36 ,$F7 ,$00 ,$FF ,$00 ,$00 ,$00 ,$00 ,$00 ,$FF ,$00 ,$F7 ,$36 ,$36 ,$36
,$36 ,$36 ,$37 ,$30 ,$37 ,$36 ,$36 ,$36 ,$00 ,$00 ,$FF ,$00 ,$FF ,$00 ,$00 ,$00
,$36 ,$36 ,$F7 ,$00 ,$F7 ,$36 ,$36 ,$36 ,$18 ,$18 ,$FF ,$00 ,$FF ,$00 ,$00 ,$00
,$36 ,$36 ,$36 ,$36 ,$FF ,$00 ,$00 ,$00 ,$00 ,$00 ,$FF ,$00 ,$FF ,$18 ,$18 ,$18
,$00 ,$00 ,$00 ,$00 ,$FF ,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$3F ,$00 ,$00 ,$00
,$18 ,$18 ,$1F ,$18 ,$1F ,$00 ,$00 ,$00 ,$00 ,$00 ,$1F ,$18 ,$1F ,$18 ,$18 ,$18
,$00 ,$00 ,$00 ,$00 ,$3F ,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$36 ,$FF ,$36 ,$36 ,$36
,$18 ,$18 ,$FF ,$18 ,$FF ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$F8 ,$00 ,$00 ,$00
,$00 ,$00 ,$00 ,$00 ,$1F ,$18 ,$18 ,$18 ,$FF ,$FF ,$FF ,$FF ,$FF ,$FF ,$FF ,$FF
,$00 ,$00 ,$00 ,$00 ,$FF ,$FF ,$FF ,$FF ,$F0 ,$F0 ,$F0 ,$F0 ,$F0 ,$F0 ,$F0 ,$F0
,$0F ,$0F ,$0F ,$0F ,$0F ,$0F ,$0F ,$0F ,$FF ,$FF ,$FF ,$FF ,$00 ,$00 ,$00 ,$00
,$00 ,$00 ,$76 ,$DC ,$C8 ,$DC ,$76 ,$00 ,$00 ,$78 ,$CC ,$F8 ,$CC ,$F8 ,$C0 ,$C0
,$00 ,$FC ,$CC ,$C0 ,$C0 ,$C0 ,$C0 ,$00 ,$00 ,$FE ,$6C ,$6C ,$6C ,$6C ,$6C ,$00
,$FC ,$CC ,$60 ,$30 ,$60 ,$CC ,$FC ,$00 ,$00 ,$00 ,$7E ,$D8 ,$D8 ,$D8 ,$70 ,$00
,$00 ,$66 ,$66 ,$66 ,$66 ,$7C ,$60 ,$C0 ,$00 ,$76 ,$DC ,$18 ,$18 ,$18 ,$18 ,$00
,$FC ,$30 ,$78 ,$CC ,$CC ,$78 ,$30 ,$FC ,$38 ,$6C ,$C6 ,$FE ,$C6 ,$6C ,$38 ,$00
,$38 ,$6C ,$C6 ,$C6 ,$6C ,$6C ,$EE ,$00 ,$1C ,$30 ,$18 ,$7C ,$CC ,$CC ,$78 ,$00
,$00 ,$00 ,$7E ,$DB ,$DB ,$7E ,$00 ,$00 ,$06 ,$0C ,$7E ,$DB ,$DB ,$7E ,$60 ,$C0
,$38 ,$60 ,$C0 ,$F8 ,$C0 ,$60 ,$38 ,$00 ,$78 ,$CC ,$CC ,$CC ,$CC ,$CC ,$CC ,$00
,$00 ,$FC ,$00 ,$FC ,$00 ,$FC ,$00 ,$00 ,$30 ,$30 ,$FC ,$30 ,$30 ,$00 ,$FC ,$00
,$60 ,$30 ,$18 ,$30 ,$60 ,$00 ,$FC ,$00 ,$18 ,$30 ,$60 ,$30 ,$18 ,$00 ,$FC ,$00
,$0E ,$1B ,$1B ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$18 ,$D8 ,$D8 ,$70
,$30 ,$30 ,$00 ,$FC ,$00 ,$30 ,$30 ,$00 ,$00 ,$76 ,$DC ,$00 ,$76 ,$DC ,$00 ,$00
,$38 ,$6C ,$6C ,$38 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$18 ,$18 ,$00 ,$00 ,$00
,$00 ,$00 ,$00 ,$00 ,$18 ,$00 ,$00 ,$00 ,$0F ,$0C ,$0C ,$0C ,$EC ,$6C ,$3C ,$1C
,$78 ,$6C ,$6C ,$6C ,$6C ,$00 ,$00 ,$00 ,$70 ,$18 ,$30 ,$60 ,$78 ,$00 ,$00 ,$00
,$00 ,$00 ,$3C ,$3C ,$3C ,$3C ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00 ,$00
);
Procedure tDiveWindow.DrawStr( x, y, col, BackCol: Integer; s: String );
type
Fontbuff = array[0..32000] of byte;
var
line,spos,bit,bpos:integer;
b: Integer;
LineBuffer : array[0..640] of byte;
ScrAddr:integer;
MaxbPos: Integer;
begin
VPTransformXY( x, y );
ScrAddr:=y*xSize+x;
MaxbPos := ySize*xSize;
for Line := 0 to 7 do
begin
bpos := ScrAddr;
for spos := 1 to length(s) do
begin
b := ord(s[spos]) shl 3+line;
for bit := 7 downto 0 do
begin
if bPos > MaxbPos then
bPos := bPos
else
if Boolean((Font8x8[b] shr bit) and 1) then
DisplayBuffer^[bpos] := Col
else
if BackCol >= 0 then
DisplayBuffer^[bpos] := backCol;
inc(bpos);
end;
end;
Inc(ScrAddr,xSize);
end;
RectChanged( x,y,x+8*length(s),y+8 );
end; // DrawStr
Procedure tDiveWindow.DrawArc( Center: Pixel; Rad, StAngle, EndAngle, Col: Integer );
begin
DrawEllipse( Center, Rad, Rad, StAngle, EndAngle, Col );
end; // DrawArc
Procedure tDiveWindow.DrawEllipse( Center: Pixel; XRad, YRad, StAngle, EndAngle, Col: Integer );
var
i : Integer;
x,y: Integer;
x1,y1,x2,y2: Integer;
v: Integer;
Multiply, Divide: Integer;
begin
If StAngle > EndAngle then SwapLong( StAngle, EndAngle );
// Modify according to aspect ratio
YRad := ( YRad * xAspect ) div yAspect;
PatternInx := 0;
Multiply := 4;
If yRad*LineThickness > 300 then
Multiply := 1
else
if yRad*LineThickness > 150 then
Multiply := 2;
Divide := 4 div Multiply;
x2 := (XRad*tCos[StAngle*4]) div 1024;
y2 := (YRad*tSin[StAngle*4]) div 1024;
LastArc.xStart := Center.x + x2;
LastArc.yStart := Center.y - y2;
for v := (StAngle+1)*Divide to EndAngle*Divide do
begin
y1 := y2;
x1 := x2;
x2 := (XRad*tCos[v*Multiply]) div 1024;
y2 := (YRad*tSin[v*Multiply]) div 1024;
DrawLine( Center.x+x2, Center.y-y2, Center.x+x1, Center.y-y1, Col );
end;
LastArc.x := Center.x;
LastArc.y := Center.y;
LastArc.xEnd := Center.x+x2;
LastArc.yEnd := Center.y-y2;
end; // DrawEllipse
Procedure tDiveWindow.DrawPieSlice( Center: Pixel; Rad, StAngle, EndAngle, Col: Integer );
var
i : Integer;
x,y: Integer;
sx,cx: Integer;
x1,y1,x2,y2: Integer;
l2dy: Double;
l1dy: Double;
a1, a2: Integer;
begin
If StAngle <> 360 then
StAngle := StAngle mod 360;
If EndAngle <> 360 then
EndAngle := EndAngle mod 360;
If StAngle > EndAngle then SwapLong( StAngle, EndAngle );
If LineMode then
// Outline
For i := StAngle*4 to EndAngle*4 do
begin
y := Center.y+(tSin[i]*Rad) div 1024;
x := Center.x+(tCos[i]*Rad) div 1024;
If (i<>StAngle*4) and (i<>EndAngle*4) then
SetPix( x, y, Col )
else
DrawLine( Center.x, Center.y, x, y, Col )
end
else
// Fill slice
begin
// Divide into one call per quadrant
for i := 0 to 3 do
if ( StAngle < i*90 ) and ( EndAngle > i*90 ) then
begin
DrawPieSlice( Center, Rad, StAngle, i*90, Col );
DrawPieSlice( Center, Rad, i*90, EndAngle, Col );
Exit;
end;
x1 := tCos[StAngle*4]; y1 := tSin[StAngle*4];
x2 := tCos[EndAngle*4]; y2 := tSin[EndAngle*4];
If StAngle = EndAngle then
begin
DrawLine( Center.x, Center.y,
Center.x+(x1*Rad) div 1024, Center.y+(y1*Rad) div 1024, Col );
Exit;
end;
if y2 <> 0 then
l2dy := x2/y2
else l2dy := 0;
if y1 <> 0 then
l1dy := x1/y1
else l1dy := 0;
For i := StAngle*4 to EndAngle*4 do
begin
x := Center.x+(tCos[i]*Rad) div 1024;
y := Center.y+(tSin[i]*Rad) div 1024;
if ( l2dy >= 0 ) and ( l1dy >= 0 ) then
begin
// 1st, 3rd Quadrant
sx := Round(l2dy*(y-Center.y)+Center.x);
DrawLine( sx, y, x, y, Col );
end
else
begin
// 2nd, 4th Quadrant
cx := Round(l1dy*(y-Center.y)+Center.x);
DrawLine( x, y, cx, y, Col );
end;
end;
If ( l1dy >= 0 ) and ( l2dy >= 0 ) then
begin
a2 := StAngle*4;
If StAngle < 90 then
a1 := 0 // 1st Quadrant
else
a1 := 180*4; // 3rd Quadrant
end
else
begin
a1 := EndAngle*4;
If StAngle <= 180 then
a2 := 180*4 // 2nd Quadrant
else
a2 := 360*4; // 4rd Quadrant
end;
For i := a1 to a2 do
begin
y := Center.y+(tSin[i]*Rad) div 1024;
x := Center.x+(tCos[i]*Rad) div 1024;
sx := Round(l2dy*(y-Center.y)+Center.x);
cx := Round(l1dy*(y-Center.y)+Center.x);
DrawLine( sx, y, cx, y, Col );
end;
end;
end; // DrawPieSlice
Procedure tDiveWindow.Flip( Steps: Longint );
var
Lines: Integer;
CopyLine: Double;
LinesLeft: Integer;
CurrLine: Integer;
BankNum : Integer;
Half: Integer;
Step: Double;
Buffer: Pointer;
p: Pointer;
Shrink,v: Double;
begin
GetMem( Buffer, xSize*ySize );
try
BankNum := 0;
DiveSwitchBank( hDive, BankNum );
p := DisplayBuffer;
for Lines := 0 to ySize-1 do
begin
move( p^, (Pchar( Buffer ) + Lines*xSize)^, xSize );
Inc( pChar(p), xSize );
end;
Inc( BankNum );
DiveSwitchBank( hDive, BankNum );
Half := ySize div 2;
Step := 3.14/Steps;
v := 0;
Repeat
if v+Step < 3.14 then
Shrink := 1/cos(v)
else
Shrink := -1;
BankNum := 0;
DiveSwitchBank( hDive, BankNum );
p := DisplayBuffer;
CurrLine := Half;
LinesLeft := ySize;
For Lines := 0 to ySize-1 do
begin
CopyLine := Half - CurrLine*Shrink;
If ( CopyLine >= 0 ) and ( CopyLine < ySize ) then
move( (pChar(Buffer) + Round(CopyLine)*xSize)^, p^, xSize )
else
FillChar( p^, xSize, 0 );
Dec( CurrLine );
Inc( pChar(p), xSize );
Dec( LinesLeft );
If LinesLeft = 0 then
begin
LinesLeft := ySize;
p := DisplayBuffer;
Inc( BankNum );
DiveSwitchBank( hDive, BankNum );
DiveBlitImage ( hDive,
fImage,
Dive_Buffer_Screen );
end;
end;
v := v + Step;
Until v > 3.14;
finally
FreeMem( Buffer, xSize*ySize );
end;
end;
procedure tDiveWindow.Clear( Col: Longint );
begin
FillChar( DisplayBuffer^, xSize*ySize, Col );
AllChanged;
end;
procedure tDiveWindow.PixelChanged( x,y: Integer );
begin
if not FastBlit then
begin
ImageChanged := True;
Exit;
end;
mtx_Rect.Request;
With fChangedRect do
begin
if x < xLeft then
xLeft := x;
if x > xRight then
xRight := x;
if y > yTop then
yTop := y;
if y < yBottom then
yBottom := y;
xLeft := max( 0, xLeft );
xRight := min( xRight, xSize-1 );
yBottom := max( 0, yBottom );
yTop := min( yTop, ySize-1 );
end;
ImageChanged := True;
mtx_Rect.Release;
end;
procedure tDiveWindow.RectChanged( x1,y1, x2,y2: Integer );
procedure PixChanged( x,y: Integer );
begin
With fChangedRect do
begin
if x < xLeft then
xLeft := x;
if x > xRight then
xRight := x;
if y > yTop then
yTop := y;
if y < yBottom then
yBottom := y;
xLeft := max( 0, xLeft );
xRight := min( xRight, xSize-1 );
yBottom := max( 0, yBottom );
yTop := min( yTop, ySize-1 );
end;
ImageChanged := True;
end;
begin
if not FastBlit then
begin
ImageChanged := True;
Exit;
end;
mtx_rect.Request;
PixChanged( x1, y1 );
PixChanged( x2, y2 );
mtx_Rect.Release;
end;
procedure tDiveWindow.AllChanged;
begin
RectChanged( 0,0, xsize-1,ysize-1);
end;
procedure tDiveWindow.WaitDraw;
begin
While fChanged or pChanged do
DosSleep(31);
end;
procedure tDiveWindow.SetLineThickness( Thickness: Word );
begin
LineThickness := ThickNess;
end;
function tDiveWindow.VPWidth: Integer;
begin
with ViewPort do
Result := x2-x1;
end;
function tDiveWindow.VPHeight: Integer;
begin
with ViewPort do
Result := y2-y1;
end;
function tDiveWindow.VPXMax: Integer;
begin
with ViewPort do
Result := x1+x2;
end;
function tDiveWindow.VPYMax: Integer;
begin
with ViewPort do
Result := y2+y1;
end;
procedure tDiveWindow.SetViewPort( xa, ya, xb, yb: Integer );
begin
With fVP do
begin
x1 := xa;
x2 := xb;
y1 := ya;
y2 := yb;
end;
end;
procedure tDiveWindow.SetLinePattern( Pattern: Word );
begin
LinePattern := Pattern;
PatternInx := 0;
end;
{&R SysUtils.Res}
procedure DisplayPMMsg( Hdr, Txt: PChar );
begin
if SuppressMessages then
Exit;
WinCreateMsgQueue(WinInitialize(0), 0);
WinMessageBox(hwnd_Desktop, hwnd_Desktop, Txt, Hdr, 0, mb_Information+mb_Moveable);
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 EDive.Create( 'Dive not installed on system. Application terminated' );
rc := DosQueryModuleName( dll_Dive, Sizeof(Buffer), Buffer );
if rc <> 0 then
raise EDive.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 EDive.Create( 'DIVE installed is very outdated and cannot be used' );
if ( Year = 1995 ) and ( Month <= 2 ) then
begin
// DIVE is from Warp, and does not support FastBlit
Os2Dive.FastBlitSupported := False;
DisplayPMMsg( 'GRAPH warning message',
'The version of DIVE found does not support optimised screen output. '+
'Because of this, screen updates using GRAPH/VP will be very slow. For better '+
'performance, apply the latest Warp Fixpak or upgrade to OS/2 Merlin' );
end
else
DisplayPMMsg( 'BGI Graphics for VP/2',
'Thank you for using Graph for Virtual Pascal with your program. Note, that '+
'this software is BETA level and is used at your own risk' );
DosFreeModule( dll_Dive );
end;
var
i : Integer;
initialization // Set up Sine and Cosine tables
if IsConsole then
begin
Writeln( 'OS2DIVE can only be used in a PM Application' );
halt(2);
end;
for i := 0 to 4*360 do
begin
tSin[i] := Round(Sin(i*pi/(4*180.0))*1024);
tCos[i] := Round(Cos(i*pi/(4*180.0))*1024);
end;
{$IFDEF DEBUG}
assign(logfile,'log.txt');
rewrite(logfile);
writeln(logfile,'Start Log');
doscreatemutexsem( nil, mtx_log, 0, False );
{$ENDIF}
VerifyDiveVersion;
end.