Introduction by Richard Russell
The commands built into BBC BASIC for Windows for displaying a bitmap image (*DISPLAY and *MDISPLAY) can only display an opaque image, i.e. anything 'underneath' the image will be obliterated. You may sometimes want to display a transparent image, that is one which has some regions in which you can see 'through' it to what lies beneath; you can do that using Windows GDI (Graphics Device Interface) API functions or BB4W library functions.
There are a number of different ways in which you can create and display a 'transparent' image:
by Michael Hutton, July 2009
How do you make a part of a bitmap transparent? One way is to use the “TransparentBlt” function supplied in MSIMG32.DLL.
First select a MODE and define some constants:
MODE 8 REM!WC IMAGE_BITMAP = 0 LR_LOADFROMFILE = &10 DIM rect{l%,t%,r%,b%} cx% = 64 : REM width cy% = 64 : REM height
Next, we have to load the MSIMG32.DLL into memory and get the address of the “TransparentBlt” function.
SYS "LoadLibrary", "MSIMG32.DLL" TO msimg32% SYS "GetProcAddress", msimg32%, "TransparentBlt" TO `TransparentBlt`
Next, load the image we want (we will assume it's in the same directory and is called star.bmp).
bmpfile$ = @dir$ + "star.bmp" SYS "LoadImage", 0, bmpfile$, IMAGE_BITMAP, cx%, cy%, LR_LOADFROMFILE TO hbitmap% IF hbitmap% = 0 THEN ERROR 100,"Cannot Load Image."
Now, because we are using GDI and we only have a handle to the bitmap we have to create a new Device Context and select our bitmap into it. (A bitmap can only be selected into one DC at a time).
SYS "CreateCompatibleDC", @memhdc% TO hdc% SYS "SelectObject", hdc%, hbitmap% TO old%
Now, we can ask GDI to transfer that bitmap into our main window. When using “TransparentBlt” we can select an RGB (COLOURREF) value to make transparent when it is drawing. It is the last parameter in “TranparentBlt”. Here I have selected 0 which is all the black bits (Red = 0, Green = 0, Blue = 0) but you can make it any colour you want. We also update a RECT{} so that we only update the region of the screen which has changed. It is much quicker to do this than update the whole window.
FOR I% = 0 TO 50 xpos% = RND(640) ypos% = RND(500) rect.l% = xpos% rect.r% = xpos% + cx% rect.t% = ypos% rect.b% = ypos% + cy% SYS `TransparentBlt`, @memhdc%, xpos%, ypos%, cx%, cy%, hdc%, 0, 0, cx%, cy%, 0 SYS "InvalidateRect", @hwnd%, rect{}, 0 WAIT 1 NEXT
Now we must remember to cleanup all the GDI objects we have created otherwise we will end up with a leak.
SYS "SelectObject", hdc%, old% SYS "DeleteDC", hdc% SYS "DeleteObject", hbitmap% SYS "FreeLibrary", msimg32% END
The example to copy and paste:
MODE 8 REM!WC IMAGE_BITMAP = 0 LR_LOADFROMFILE = &10 DIM rect{l%,t%,r%,b%} SYS "LoadLibrary", "MSIMG32.DLL" TO msimg32% SYS "GetProcAddress", msimg32%, "TransparentBlt" TO `TransparentBlt` cx% = 64 cy% = 64 bmpfile$ = @dir$ + "star.bmp" SYS "LoadImage", 0, bmpfile$, IMAGE_BITMAP, cx%, cy%, LR_LOADFROMFILE TO hbitmap% IF hbitmap% = 0 THEN ERROR 100,"Cannot Load Image." SYS "CreateCompatibleDC", @memhdc% TO hdc% SYS "SelectObject", hdc%, hbitmap% TO old% FOR I% = 0 TO 50 xpos% = RND(640) ypos% = RND(500) rect.l% = xpos% rect.r% = xpos% + cx% rect.t% = ypos% rect.b% = ypos% + cy% SYS `TransparentBlt`, @memhdc%, xpos%, ypos%, cx%, cy%, hdc%, 0, 0, cx%, cy%, 0 SYS "InvalidateRect", @hwnd%, rect{}, 0 WAIT 1 NEXT SYS "SelectObject", hdc%, old% SYS "DeleteDC", hdc% SYS "DeleteObject", hbitmap% SYS "FreeLibrary", msimg32% END
And there we are! Enjoy.
Michael Hutton