home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
vpbgib1.zip
/
OS2DIVE.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-08-10
|
71KB
|
2,133 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; // 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;
type
Pixel = Record
x,y: SmallInt;
end;
tRect = Record
x1,y1, x2,y2: SmallInt;
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;
fStatistics: Boolean;
fPauseDisplay: Boolean;
pPalette: Pointer;
PaletteChanged: Set of 0..255;
pChanged: Boolean;
fChanged: Boolean;
fChangedRect: RectL;
OldPal: HPs;
PSPal: HPS;
SetupBlitter : SETUP_BLITTER;
fFrameRate: Double; // Current frame rate (frames per second)
fFrameTime: Double; // Current time to display one frame (seconds)
mtx_Update: HMtx;
mtx_Palette: HMtx;
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 SetStatistics( b: Boolean);
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 Statistics: Boolean read fStatistics write SetStatistics;
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 FrameRate: Double read fFrameRate; // Frames per second
property FrameTime: Double read fFrameTime; // Time per frame
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;
// 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 ) );
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;
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
WinSetWindowPos ( MyDive.hwndFrame, HWND_TOP,
0, 0, // Ignored
GetSnapWidth( MyDive.xSize*2 ),
GetSnapHeight( MyDive.ySize*2 ),
SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
ID_SNAPFULL:
// Snap to Full Size but retain (approx) aspect ratio
With MyDive do
WinSetWindowPos ( hwndFrame, HWND_TOP,
0,
screeny div 2-((fSizeY*ScreenX) div fSizeX) div 2,
ScreenX,
(fSizeY*ScreenX) div fSizeX,
SWP_MOVE or SWP_SIZE or SWP_ACTIVATE or SWP_SHOW );
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 );
end
else
DiveSetupBlitter ( MyDive.hDive, nil );
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_F3 : WinPostMsg ( Window, WM_QUIT, 0, 0 );
VK_F1 : WinPostMsg ( Window, WM_COMMAND, ID_SNAP, 0 );
VK_F2 : WinPostMsg ( Window, WM_COMMAND, ID_SNAP2, 0 );
VK_F4 : WinPostMsg ( Window, WM_COMMAND, ID_SNAPFULL, 0 );
VK_F5 : WinPostMsg ( Window, WM_COMMAND, ID_PAUSE, 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;
procedure GetMtxOwner( MyDive: tDiveWindow );
var
rc : Longint;
pid : pPid;
tid : pTid;
count : Longint;
begin
// rc := DosQueryMutexSem( MyDive.mtx_Update, (* Handle of semaphore *)
// pid, (* Process ID of owner *)
// tid, (* Thread ID of owner *)
// count); (* Count *)
//
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;
Frames: Longint; // Frame counter
StartTimer :Longint;
rc: ApiRet;
PostCount:Longint;
Time0,time1,TotalTime: Longint;
TotalFrames : Longint;
NewBlitter: Setup_Blitter;
swpos :SWP; (* Window position *)
point_l :POINTL; (* Point to offset from Desktop *)
xRatio : Double;
yRatio : Double;
begin
MyDive := tDiveWindow( P );
Frames:=0;
TotalTime := 0;
TotalFrames := 0;
// Set up colour palette
if ColTranslate then
With MyDive do
DiveSetSourcePalette ( hDive, 0, Colours, pPalette );
try
StartTimer := GetTime;
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 and
( DosRequestMutexSem( mtx_Update, 800 ) = 0 ) then
// Make image appear in window
if fChanged then
begin
Time0 := GetTime;
if FastBlit then
begin
// Accelerated blit routine
WinQueryWindowPos ( hwndClient, swpos );
xRatio := swpos.cx / xSize;
yRatio := swpos.cy / ySize;
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;
// Source rectangle
ulSrcPosX := fChangedRect.xLeft;
ulSrcPosY := fChangedRect.yBottom;
ulSrcWidth := min( xsize-ulSrcPosX, fChangedRect.xRight - fChangedRect.xLeft + 1 );
ulSrcHeight := min( ysize-ulSrcPosY, fChangedRect.yTop - fChangedRect.yBottom + 1 );
// Destination rectangle
lDstPosX := Round(xRatio*ulSrcPosX);
lDstPosY := swpos.cy-1-Round(yRatio*fChangedRect.yTop);
ulDstWidth := Round(xratio*ulSrcWidth);
ulDstHeight := Round(yratio*ulSrcHeight);
{ If LDstPosY + ulDstHeight > swPos.y then
LDstPosY := swPos.y - ulDstHeight;}
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
if DiveBlitImage ( hDive, fImage, dive_Buffer_Screen ) <> 0 then ;
with fChangedRect do
begin
xLeft := xsize;
xRight := 0;
yTop := 0;
yBottom := ySize;
end;
fChanged := False;
Time1 := GetTime;
inc(frames);
Inc( TotalTime, Time1-Time0 );
DosReleaseMutexSem( mtx_Update );
end
else
begin
DosReleaseMutexSem( mtx_Update );
// Nothing to do - wait for timer
rc := DosWaitEventSem( TimerEvent, 200 );
if rc = 6 then exit;
DosResetEventSem(TimerEvent,postcount);
end
else
; // GetMtxOwner( MyDive );
// Increase whether updated or not
Inc( TotalFrames );
// Update FrameRate and FrameTime statistics
if (TotalFrames > 10) then
begin
Time1 := GetTime;
If Frames > 0 then
fFrameTime := TotalTime/Frames
else
fFrameTime := 0;
If Time1 <> StartTimer then
fFrameRate := 1000*TotalFrames/(Time1-StartTimer)
else
fFrameRate := 0;
Frames := 0;
TotalTime := 0;
StartTimer := Time1;
TotalFrames := 0;
If Statistics then
SetMainWindowTitle( Format( '%2.6g Fps', [Framerate] ));
end;
end;
except
{$IFDEF DEBUG}
on e:exception do
log( 'Blit Exception: '+e.message );
{$ENDIF}
end;
end;
function tDiveWindow.BeginUpdate: Integer;
var
ulScanLineBytes:ULONG;
ulScanLines:ULONG;
begin
if DosRequestMutexSem( mtx_Update, 1000 ) <> 0 then
begin
GetMtxOwner( Self );
Result := -1;
Exit;
end;
Result := DiveBeginImageBufferAccess ( // <> 0 = error
hDive,
fImage,
Pointer( fDisplayBuf ),
ulScanLineBytes,
ulScanLines );
end;
procedure tDiveWindow.EndUpdate;
begin
DiveEndImageBufferAccess ( hDive, fImage );
DosReleaseMutexSem( mtx_Update );
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
if DosRequestMutexSem( mtx_Palette, 1000 ) <> 0 then
break;
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];
DosReleaseMutexSem( mtx_Palette );
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
if DosRequestMutexSem( mtx_Palette, 800 ) = 0 then
begin
with p_rgbxpal8(pPalette)^[ Num ] do
begin
r := red;
g := green;
b := blue;
end;
PaletteChanged := PaletteChanged + [Num];
pChanged := True;
ImageChanged := True;
AllChanged;
DosReleaseMutexSem( mtx_Palette );
end;
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;
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 );
WinSetWindowULong( hwndClient, 0, Longint(Self) );
WinSetVisibleRegionNotify ( hwndClient, TRUE );
WinPostMsg ( hwndFrame, WM_VRNENABLED, 0, 0 );
Stopping := False;
Statistics := False;
LineMode := False;
PauseDisplay := False;
UpdateBuffer := nil;
MessageHandler := nil;
pChanged := False;
PaletteChanged := [];
fChanged := True;
fFrameRate := 0;
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 := True;
DoscreateMutexSem( nil, mtx_Update, 0, False );
DoscreateMutexSem( nil, mtx_Palette, 0, False );
DosCreateEventSem( nil, TimerEvent, 0, False );
AllChanged;
// Blitter thread
tidBlitThread := VPBeginThread ( BlitterThread, 4*16384, Self );
DosSetPriority ( prtys_Thread, prtyc_Regular, 0, 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 );
DosCloseMutexSem( mtx_Update );
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;
procedure tDiveWindow.SetStatistics( b: Boolean);
begin
if b and not fStatistics then
// Save current window title
;
if not b and Statistics then
// Restore window title
;
fStatistics := b;
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
( ( ( x >= x1 ) and ( x <= x2 ) and
( y >= y1 ) and ( y <= y2 ) ) or not VPClip );
if not result then
x := x;
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 ];
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 ebx}
procedure Swap( var a,b: Longint );
{var
h : Longint;
begin
h := a;
a := b;
b := h;}
asm
mov eax,a
mov ebx,b
mov ecx,[eax] // Value of a
mov edx,[ebx] // Value of b
mov [eax],edx
mov [ebx],ecx
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 Swap( 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;
// 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;
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
Swap( x1, x2 );
If VPClip then
begin
// Clip to viewport
x1 := max( x1, ViewPort.x1 );
x2 := min( x2, VPXMax );
y1 := max( ViewPort.y1, min( y1+ltd2, ViewPort.y2-ltd2 ) );
end
else
begin
x1 := max( 0, x1 );
x2 := min( xSize-1, x2 );
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
Swap( x1, x2 );
Swap( y1, y2 );
end;
SetWinPix( x1, y1, c );
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 );
if LineThickness = 3 then
begin
Dec( PatternInx );
SetWinPix( x, sy.i-1, c );
Dec( PatternInx );
SetWinPix( x, sy.i+1, c );
end;
end;
end;
end // dX > dY
else
begin
if y2 < y1 then
begin
Swap( x1, x2 );
Swap( y1, y2 );
end;
SetWinPix( x1, y1, c );
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 );
if LineThickness = 3 then
begin
Dec( PatternInx );
SetWinPix( sx.i-1, y, c );
Dec( PatternInx );
SetWinPix( sx.i+1, y, c );
end;
end;
end;
end; // dY > dX
SetWinPix( x2, y2, c );
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 Swap( x1, x2 );
if (y1 > y2) then Swap( 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 Swap( longint(p1), longint(p2) );
if p1.y > p3.y then Swap( longint(p1), longint(p3) );
if p2.y > p3.y then Swap( longint(p2), longint(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;
Pixels[ 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;
Pixels[ ex.i, p1.y ] := c;
Pixels[ 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
Pixels[ 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 Swap( Longint( p1 ), Longint( p2 ) );
if p1.y > p3.y then Swap( Longint( p1 ), Longint( p3 ) );
if p1.y > p4.y then Swap( Longint( p1 ), Longint( p4 ) );
if p2.y > p3.y then Swap( Longint( p2 ), Longint( p3 ) );
if p2.y > p4.y then Swap( Longint( p2 ), Longint( p4 ) );
if p3.y > p4.y then Swap( Longint( p3 ), Longint( 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;
Pixels[ 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;
begin
If StAngle > EndAngle then Swap( StAngle, EndAngle );
// Modify according to aspect ratio
YRad := ( YRad * xAspect ) div yAspect;
PatternInx := 0;
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 to EndAngle do // Quarter circle
begin
y1 := y2;
x1 := x2;
x2 := (XRad*tCos[v*4]) div 1024;
y2 := (YRad*tSin[v*4]) 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 Swap( 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
Pixels[ 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
BeginUpdate;
FillChar( DisplayBuffer^, xSize*ySize, Col );
EndUpdate;
AllChanged;
end;
procedure tDiveWindow.PixelChanged( x,y: Integer );
begin
if not FastBlit then
Exit;
if DosRequestMutexSem( mtx_Update, 900 ) <> 0 then
begin
GetMtxOwner( Self );
Exit;
end;
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;
DosReleaseMutexSem( mtx_Update );
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 DosRequestMutexSem( mtx_Update, 1000 ) <> 0 then
begin
GetMtxOwner( Self );
Exit;
end;
PixChanged( x1, y1 );
PixChanged( x2, y2 );
DosReleaseMutexSem( mtx_Update );
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}
var
i : Integer;
initialization // Set up Sine and Cosine tables
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}
end.