Contributor: VARIOUS AUTHORS 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.