unit WinG; {WinG import unit for Borland Pascal}
interface
uses winTypes;
function WinGCreateDC:hDC;
function WinGRecommendDIBFormat(pFormat:pBitmapInfo):boolean;
function WinGCreateBitmap(WinGDC:hDC; pHeader:pBitmapInfo; var
ppBits:pointer):hBitmap;
function WinGGetDIBPointer(WinGBitmap:hBitmap;
pHeader:pBitmapInfo):pointer;
function WinGGetDIBColorTable(WinGDC:hDC; StartIndex, NumberOfEntries:word;
pColors:pointer):word;
function WinGSetDIBColorTable(WinGDC:hDC; StartIndex, NumberOfEntries:word;
pColors:pointer):word;
function WinGCreateHalftonePalette:hPalette;
type tWinGDither=(winG4x4Dispersed,winG8x8Dispersed,winG4x4Clustered);
function WinGCreateHalftoneBrush(context:hDC; crColor:tColorRef;
ditherType:tWinGDither):hBrush;
function WinGBitBlt(hdcDst:hDC; nXOriginDst, nYOriginDst, nWidthDst,
nHeightDst:integer;
hdcSrc:hDC; nXOriginSrc, nYOriginSrc:integer):boolean;
function WinGStretchBlt(hdcDst:hDC; nXOriginDst, nYOriginDst, nWidthDst,
nHeightDst:integer;
hdcSrc:hDC; nXOriginSrc, nYOriginSrc, nWidthSrc,
nHeightSrc:integer):boolean;
implementation
function WinGCreateDC:hDC; external 'WinG';
function WinGRecommendDIBFormat; external 'WinG';
function WinGCreateBitmap; external 'WinG';
function WinGGetDIBPointer; external 'WinG';
function WinGGetDIBColorTable; external 'WinG';
function WinGSetDIBColorTable; external 'WinG';
function WinGCreateHalftonePalette; external 'WinG';
function WinGCreateHalftoneBrush; external 'WinG';
function WinGBitBlt; external 'WinG';
function WinGStretchBlt; external 'WinG';
end.
Here is an example of how to implement Delphi with WING..
{$A+,B-,D-,F+,G+,I-,K-,L-,N-,P-,Q-,R-,S-,T-,V-,W-,X+,Y-}
{$M 8192,8192}
PROGRAM BPWinG;
{ - Demonstration of WinG with Borland Pascal
Written by Lars Fosdal, lfosdal@falcon.no,
Initial version: 11 NOV 1994
Version 2: 24 NOV 1994
Released to the public domain, 11 NOV 1994
Based on:
WinG DLL import unit
by Matthew R Powenski, dv224@cleveland.Freenet.Edu
STATIC - A WinG Sample Application (written in C)
by Robert B. Hess, Microsoft Corp.
flames.pas from the SWAG libraries (DOS VGA demo)
by Keith Degrâce, ekd0840@bosoleil.ci.umoncton.ca.
or 9323767@info.umoncton.ca
Note: WinG must be installed before this program can be run.
Hopefully, the latest version of this program can be found as
garbo.uwasa.fi:/windows/turbopas/bpwing##.zip
where ## is a version number.
Comments:
Actually, this is a pretty lame demo (source translated, ideas stolen,
performance sucks, usability nil), but it shows you the general idea
of WinG. On a VL or PCI local bus graphics adapter, the performance
isn't to bad, but it gets real slow on ISA-only cards.
In an intelligent WinG app. you don't usually repaint the entire
bitmap,
but only the changed sections. You would also tune the bitmap
generation
and manipulation routines with assembly, and apply the usual bag of
animations tricks.
However, thats for you to do! Have fun!
Changes, Version 2:
- Range error caused GPF under Win16 (Wonder why it worked under
Win32/WOW?)
- Fixed bitmap orientation problem (Didn't work on bottom-up
oriented bmps)
- Restructured and added run-time selectable animation style
- added more comments
And:
Yep, I know I should have erased the bitmap before I changed the
palette
to avoid the "wrong color" flash... You do it :-)
Thanks to:
Eivind Bakkestuen (hillbilly@programmers.bbs.no)
for reporting the GPF problem in the initial release.
Timo Salmi, Ari Hovila, and Jouni Ikonen
for keeping garbo.uwasa.fi a great site to visit.
}
USES
{$IFDEF Debug}
WinCRT,
{$ENDIF}
WinTypes, WinProcs, oWindows, oDialogs, WinG;
{$R BPWinG.RES}
{.DEFINE x2} {Stretch to 2 x Size (A _LOT_ Slower :-( )}
CONST {Image sizes (flames demo doesn't adapt too well, though)}
ImageX = 320; {Must be a multiple of two}
ImageY = 200; {ImageX x ImageY must not exceed 64K}
{(Unless you want to write your own array access methods...
I _REALLY_ want a 32 bit Pascal :-))}
TYPE
pScreen = ^TScreen; {Bitmap access table}
TScreen = RECORD
CASE Integer OF
0 : (ptb : ARRAY[-(ImageY-1)..0, 0..ImageX-1] OF Byte);
{ptb = byte coord [y, x]}
1 : (ptw : ARRAY[-(ImageY-1)..0, 0..(ImageX DIV 2)-1] OF Word);
{ptw = word coord [y, x div 2]}
2 : (pta : ARRAY[0..(ImageY*ImageX)-1] OF Byte);
{pta = byte array [(y*320)+x]}
END; {REC TScreen}
TImage = RECORD {DIB Information}
bi : TBitmapInfoHeader;
aColors : ARRAY[0..255] OF TRGBQUAD;
END; {REC TImage}
TPalette = RECORD {Palette Information}
Version : Word; {set to $0300 (Windows version 3.0)}
NumberOfEntries : Word; {set to 256}
aEntries : ARRAY[0..255] OF TPaletteEntry;
END; {REC TPalette}
pWinGApp = ^TWinGApp; {OWL Application}
TWinGApp = OBJECT(TApplication)
PROCEDURE InitMainWindow; VIRTUAL;
END; {OBJ TWinGApp}
pWinGWin = ^TWinGWin; {OWL Window}
TWinGWin = OBJECT(TWindow)
LogicalPalette : TPalette; {Our palette initialization table}
hPalApp : hPalette; {Our palette}
Image : TImage; {Our bitmap initialization table}
hdcImage : hDC; {Our WinG DC}
hOldBitmap : hBitmap; {Ye olde bitmap of the WinG DC must be restored}
bmp : pScreen; {Assistant bitmap pointer}
Orientation : Integer; {Indicates bitmap orientation, 1=top-down
-1=bottom-up}
Direction : Integer; {Determines animation direction 1=Up
-1=Down}
CONSTRUCTOR Init(aParent:pWindowsObject; aTitle:pChar);
DESTRUCTOR Done; VIRTUAL;
PROCEDURE GetWindowClass(VAR aWndClass:TWndClass); VIRTUAL;
PROCEDURE SetupWindow; VIRTUAL;
PROCEDURE SetDirection(NewDirection:Integer);
PROCEDURE wmEraseBkGnd(VAR Msg:TMessage); VIRTUAL wm_First +
wm_EraseBkGnd;
PROCEDURE wmPaletteChanged(VAR Msg:TMessage); VIRTUAL wm_First +
wm_PaletteChanged;
PROCEDURE wmQueryNewPalette(VAR Msg:TMessage); VIRTUAL wm_First +
wm_QueryNewPalette;
PROCEDURE wmTimer(VAR Msg:TMessage); VIRTUAL wm_First +
wm_Timer;
PROCEDURE Paint(PaintDC:hDC; VAR PaintInfo:TPaintStruct); VIRTUAL;
PROCEDURE cmAbout(VAR Msg:TMessage); VIRTUAL cm_First +
100;
PROCEDURE cmQuit(VAR Msg:TMessage); VIRTUAL cm_First +
101;
PROCEDURE cmDirection(VAR Msg:TMessage); VIRTUAL cm_First +
102;
END; {OBJ TWinGWin}
{////////////////////////////////////////////////////////////////
TWinGApp ///}
PROCEDURE TWinGApp.InitMainWindow;
BEGIN
MainWindow:=New(pWinGWin, Init(nil, 'WinG + Pascal!'));
END; {PROC TWinGApp.InitMainWindow}
{////////////////////////////////////////////////////////////////
TWinGWin ///}
CONSTRUCTOR TWinGWin.Init(aParent:pWindowsObject; aTitle:pChar);
BEGIN
Inherited Init(aParent, aTitle);
Attr.Style:=ws_PopupWindow or ws_Caption;
Attr.x:=160;
Attr.y:=110;
Attr.w:={$IFDEF x2}2* {$ENDIF}ImageX + (2 * GetSystemMetrics(sm_CXBorder));
Attr.h:={$IFDEF x2}2* {$ENDIF}ImageY + (2 * GetSystemMetrics(sm_CYBorder))
+ GetSystemMetrics(sm_CYCaption)
+ GetSystemMetrics(sm_CYMenu);
Attr.Menu:=LoadMenu(hInstance, pChar('WinG_MNU'));
hPalApp:=0;
hdcImage:=0;
hOldBitmap:=0;
Orientation:=1;
Direction:=1;
END; {CONS TWinGWin.Init}
DESTRUCTOR TWinGWin.Done;
VAR
hbm : hBitmap;
BEGIN
IF Bool(hDCImage) {If we have a valid DC handle}
THEN BEGIN
hbm:=SelectObject(hdcImage, hOldBitmap); {Restore old bitmap}
DeleteObject(hBM); {Delete our bitmap}
DeleteDC(hdcImage); {Delete our DC}
END;
IF Bool(hPalApp) {If we have a valid palette handle}
THEN DeleteObject(hPalApp); {delete our palette}
KillTimer(hWindow, 1); {Kill our timer}
Inherited Done; {Leave the rest to OWL}
END; {DEST TWinGWin.Done}
PROCEDURE TWinGWin.GetWindowClass(VAR aWndClass:TWndClass);
BEGIN
Inherited GetWindowClass(aWndClass);
aWndClass.hIcon:=LoadIcon(hInstance, pChar('WinG_ICO')); {Load our Icon}
aWndClass.Style:=cs_ByteAlignClient or cs_VRedraw or cs_HRedraw or
cs_DblClks;
END; {PROC TWinGWin.GetWindowClass}
PROCEDURE TWinGWin.SetupWindow;
VAR
Desktop : hDC; {Get the system colors via the Desktop DC}
i : Integer; {general purpose}
BEGIN
Inherited SetupWindow; {Let OWL do it's part}
Randomize;
SetTimer(hWindow, 1, 40, nil); {Create our timer (40ms = 25
paints/sec)}
FillChar(Image, SizeOf(Image), 0); {Better safe than sorry}
{Ask WinG about the preferred bitmap format}
IF WinGRecommendDIBFormat(pBitmapInfo(@Image.Bi))
THEN BEGIN
Image.Bi.biBitCount:=8; {Force to 8 bits per pixel}
Image.Bi.biCompression:=bi_RGB; {Force to no compression}
Orientation:=Image.bi.biHeight; {Get height}
END
ELSE WITH Image.bi {If WinG failed to initialize our image
info}
DO BEGIN {we'll do it ourselves}
biSize:=SizeOf(Image.bi);
biPlanes:=1;
biBitCount:=8;
biCompression:=bi_RGB;
biSizeImage:=0;
biClrUsed:=0;
biClrImportant:=0;
Orientation:=1;
END;
Image.bi.biWidth:=ImageX; {Define the image sizes}
Image.bi.biHeight:=ImageY * Orientation;
image.bi.biSizeImage := (image.bi.biWidth * image.bi.biHeight);
image.bi.biSizeImage := image.bi.biSizeImage*Orientation;
Desktop:=GetDC(0); {Setup our palette init info and get the 20 system
colors}
LogicalPalette.Version:=$0300;
LogicalPalette.NumberOfEntries:=256;
GetSystemPaletteEntries(Desktop, 0, 10, LogicalPalette.aEntries);
GetSystemPaletteEntries(Desktop, 246, 10, LogicalPalette.aEntries[246]);
ReleaseDC(0, Desktop);
FOR i:=0 TO 9 {Duplicate the system colors into the bitmap}
DO BEGIN
Image.aColors[i].rgbRed :=LogicalPalette.aEntries[i].peRed;
Image.aColors[i].rgbGreen:=LogicalPalette.aEntries[i].peGreen;
Image.aColors[i].rgbBlue :=LogicalPalette.aEntries[i].peBlue;
Image.aColors[i].rgbReserved:=0;
LogicalPalette.aEntries[i].peFlags:=0;
Image.aColors[i+246].rgbRed :=LogicalPalette.aEntries[i].peRed;
Image.aColors[i+246].rgbGreen:=LogicalPalette.aEntries[i].peGreen;
Image.aColors[i+246].rgbBlue :=LogicalPalette.aEntries[i].peBlue;
Image.aColors[i+246].rgbReserved:=0;
LogicalPalette.aEntries[i+246].peFlags:=0;
END;
hdcImage:=WinGCreateDC; {Get our WinG DC}
SetDirection(1);
END; {PROC TWinGWin.SetupWindow}
PROCEDURE TWinGWin.SetDirection(NewDirection:Integer);
PROCEDURE SetRgb(i,r,g,b:Byte);
CONST
c = 4; {Scale up the DOS colors to fit a 24-bit palette}
BEGIN
LogicalPalette.aEntries[i].peRed := r*c;
LogicalPalette.aEntries[i].peGreen := g*c;
LogicalPalette.aEntries[i].peBlue := b*c;
Image.aColors[i].rgbRed :=LogicalPalette.aEntries[i].peRed;
Image.aColors[i].rgbGreen:=LogicalPalette.aEntries[i].peGreen;
Image.aColors[i].rgbBlue :=LogicalPalette.aEntries[i].peBlue;
Image.aColors[i].rgbReserved:=0;
LogicalPalette.aEntries[i].peFlags:=PC_NOCOLLAPSE;
END;
VAR
i : Integer;
hbm : hBitmap; {Handle to our bitmap}
mnu : hMenu;
BEGIN
Direction:=NewDirection;
mnu:=GetMenu(hWindow);
IF Direction=1
THEN BEGIN
SetWindowText(hWindow,'WinG + Pascal = Hot!');
ModifyMenu(mnu, 102, mf_ByCommand, 102, 'C&ool!');
FOR i := 1 TO 32 {Build Black->Red->Yellow->White colors}
DO BEGIN
SetRgb(i, (i shl 1)-1, 0, 0 );
SetRgb(i+32, 63, (i shl 1)-1, 0 );
SetRgb(i+64, 63, 63, (i shl 1)-1 );
SetRgb(i+96, 63, 63, 63 );
END
END
ELSE BEGIN
SetWindowText(hWindow,'WinG + Pascal = Cool!');
ModifyMenu(mnu, 102, mf_ByCommand, 102, 'H&ot!');
FOR i := 1 TO 32 {Build Black->Blue->Cyan->White colors}
DO BEGIN
SetRgb(i, 0, 0, (i shl 1)-1);
SetRgb(i+32, 0, (i shl 1)-1, 63 );
SetRgb(i+64, (i shl 1)-1, 63, 63 );
SetRgb(i+96, 63, 63, 63 );
END;
END;
DrawMenuBar(hWindow);
IF Bool(hOldBitmap)
THEN BEGIN
DeleteObject(hPalApp);
DeleteObject(SelectObject(hDCImage, hOldBitmap));
END;
hPalApp:=CreatePalette(pLogPalette(@LogicalPalette)^);
hBM:=WinGCreateBitmap(hdcImage, pBitmapInfo(@Image.Bi), @bmp);
hOldBitmap:=SelectObject(hdcImage, hBM); {Associate the bitmap with the DC}
PatBlt(hDCImage, 0,0, ImageX, ImageY, BLACKNESS); {Paint the bitmap black}
InvalidateRect(hWindow, nil, True);
END; {PROC TWinGWin.SetDirection}
PROCEDURE TWinGWin.wmEraseBkGnd(VAR Msg:TMessage);
BEGIN
Bool(Msg.Result):=True; {We don't want Windows to erase our background}
END; {FUNC TWinGWin.wmEraseBkGnd}
PROCEDURE TWinGWin.wmPaletteChanged(VAR Msg:TMessage);
BEGIN {If some other Windows app has focus and
changed}
IF Msg.wParam=hWindow {the system colors, we'll update too so
that we}
THEN wmQueryNewPalette(Msg); {can get the second best choices}
END; {PROC TWinGWin.wmPaletteChanged}
PROCEDURE TWinGWin.wmQueryNewPalette(VAR Msg:TMessage);
{ - Update palette and repaint if changed}
VAR
DC : hDC;
ReMappedColors:Word;
BEGIN
DC:=GetDC(hWindow);
IF Bool(hPalApp)
THEN SelectPalette(DC, hPalApp, False);
ReMappedColors:=RealizePalette(DC);
ReleaseDC(hWindow, DC);
IF (ReMappedColors > 0)
THEN BEGIN
InvalidateRect(hWindow, nil, True);
Bool(Msg.Result):=True;
END
ELSE Bool(Msg.Result):=False;
END; {PROC TWinGWin.wmQueryNewPalette}
PROCEDURE TWinGWin.wmTimer(VAR Msg:TMessage);
BEGIN
InvalidateRect(hWindow, nil, False); {Force a repaint}
END; {PROC TWinGWin.wmTimer}
PROCEDURE TWinGWin.Paint(PaintDC:hDC; VAR PaintInfo:TPaintStruct);
VAR
x,y,
x2,y2,c : Integer;
one, two : Integer;
BEGIN
SelectPalette(PaintDC, hPalApp, False); {Select our palette}
RealizePalette(PaintDC); {and map it to the system palette}
IF not Assigned(bmp)
THEN Exit;
WITH bmp^ {With our bitmap bits}
DO BEGIN
one:=1*Orientation*Direction;
two:=2*Orientation*Direction;
FOR x := 0 TO 159 {Update the flame bitmap}
DO BEGIN
x2:=x shl 1;
FOR y := 30 TO 98
DO BEGIN
IF Orientation=Direction
THEN y2:=-(y shl 1)
ELSE y2:=-200+(y shl 1);
c := (ptb[y2,x2]
+ ptb[y2,x2+2]
+ ptb[y2,x2-2]
+ ptb[y2-two,x2+2]) shr 2;
IF c <> 0 THEN dec(c);
ptw[y2+two, x] := Word(c or (c shl 8));
ptw[y2+one, x] := Word(c or (c shl 8));
END;
ptb[y2,x2] := random(2)*160;
END;
END;
{$IFDEF x2}
WinGStretchBlt(PaintDC, 0,0, 2*ImageX, 2*ImageY, hdcImage, 0,0, ImageX,
ImageY);
{$ELSE}
WinGBitBlt(PaintDC, 0,0, ImageX, ImageY, hdcImage, 0,0);
{$ENDIF}
END; {PROC TWinGWin.Paint}
PROCEDURE TWinGWin.cmAbout(VAR Msg:TMessage);
VAR
Dlg : pDialog;
BEGIN
New(Dlg, Init(@Self, pChar('WinG_DLG')));
Dlg^.Execute;
Dispose(Dlg, Done);
END; {PROC TWinGWin.cmAbout}
PROCEDURE TWinGWin.cmDirection(VAR Msg:TMessage);
BEGIN
SetDirection(-Direction);
END; {PROC TWinGWin.cmDirection}
PROCEDURE TWinGWin.cmQuit(VAR Msg:TMessage);
BEGIN
CloseWindow;
END; {PROC TWinGWin.cmQuit}
VAR
App : pWinGApp;
BEGIN
New(App, Init('BPWinG'));
App^.Run;
Dispose(App, Done);
END.