BBC BASIC for Windows
Programming >> Graphics and Games >> Transparent colours
http://bb4w.conforums.com/index.cgi?board=graphics&action=display&num=1477399912

Transparent colours
Post by KenDown on Oct 25th, 2016, 12:51pm

In the Gimp (and no doubt in Photoshop as well) you can set the transparency of colours so that what is underneath can be seen - a bit like a highlight marker.

Does anyone have any idea how to do this in BBC BASIC? I want to RECTANGLEFILL an area on my screen but have what is underneath still visible, just coloured or tinted.
Re: Transparent colours
Post by DDRM on Oct 25th, 2016, 3:57pm

Hi Kendall,

As far as I know, you can't do true transparency in "pure" basic, though you could get something like it with careful use of GCOL mode 1, which will "add" the new colour while also leaving the existing colour in place. Note the clarification in the "compatibility limitations" section on how this works - it acts on the physical colours, not the logical colours.
Code:
      MODE 21
      GCOL 4
      RECTANGLE 100,100,400,100
      GCOL 1
      CIRCLE FILL 300,200,100
      VDU 5
      GCOL 15
      MOVE 120,140
      PRINT"Hello world!"
      VDU 4
      COLOUR 2,0,40,0:REM A rather faint green as a highlighter
      GCOL 1,2
      RECTANGLE FILL 150,80,500,200 


I don't think "proper" transparency is do-able without fiddling, because I think the normal output bitmap is a 24 bit one. I suspect that to play with transparency you would need to use Windows API commands, such as AlphaBlend, to copy data from another (32 bit) bitmap.

It looks like it may be a bit complicated because you may have to pre-multiply the bitmap (in other words, scale all the RGB colour data by the transparency), which seems a bit daft to me, but there you are. Presumably there are functions to do that.

You may be able to use AlphaBlend without 32 bit source data or premultiplication if you use the SourceConstantAlpha value to make the whole thing you are adding a constant transparency.

I may have a play with this to see if I can make it work. If David Williams is reading, he can probably answer immediately... ?? :-)

D
Re: Transparent colours
Post by KenDown on Oct 25th, 2016, 5:36pm

Thanks, though none of those will do what I want.

I have a transparent window overlaid on another window. What I want is to put a square of colour in the transparent window but still be able to see what is in the window underneath. As the text/picture is not in the transparent window, using GCOL2 or GCOL3 will not work.

With the Gimp you can have a separate layer (which I am assuming is a separate and transparent window) into which you load a picture, then drag a slider to progressively alter the transparency of the upper layer. That is the sort of effect for which I am looking.
Re: Transparent colours
Post by michael on Oct 26th, 2016, 05:46am

One option is to capture the area in question and overlay it with the image you want, and use * REFRESH to show the overlay. Then reload the image and place it back in the overlay area then move your overlay as required.
Also, for an overlay, you may try a sprite.

If you look in the TOOLS section I made a automatic mask and sprite creation tool that might be helpful. I also made a getpic and putpic tool that you may want to experiment with. I think I know a few ways to make a transparent overlay. As soon as I get my animation tool done I will work on it..
Re: Transparent colours
Post by DDRM on Oct 26th, 2016, 07:56am

OK, I can see that's a different situation....

What happens if you select a 32 BPP bitmap (you'll probably need to use a DIBsection, so you can modify it directly) into your transparent window, and then set the top bytes to control the transparency? I'm not sure if Windows will automatically use that transparency data...

Doing it that way, of course, you could use that approach to make the whole window completely transparent, which would mean you don't need to use the wiki approach to generate the (complete) transparency, which may or may not be an advantage.

Best wishes,

D


Re: Transparent colours
Post by DDRM on Oct 27th, 2016, 08:03am

Richard passed by the forum, and points out that there IS a simple solution: use the GDIPLIB library. Using GDIPlus you can define translucent brushes (just set the relevant bits of the colour you send to FN_gdipcreatebrush, which should be &AARRGGBB: the AA determines how solid the colour is), then use PROC_gdippolygon(brush%, vertices%, x(), y(), fmode%)
to draw your rectangle.

You will find the section on the GDIP library under "antialiased graphics", since that is one of the huge advantages of using the GDIP system.

Best wishes,

D
Re: Transparent colours
Post by KenDown on Oct 27th, 2016, 5:07pm

Thanks to everyone for your replies. That GDIPLIB sounds interesting. I will have to explore it.

Thanks again.
Re: Transparent colours
Post by KenDown on Oct 31st, 2016, 10:54am

Oh grrrr!

Is it just me or is it a "feature" of the GDIPLIB?

I've got the darn thing working and it draws beautiful transparent colours - but it will only draw them in the main window. Using MULTIWIN and setting to PROC_selectwin(1) makes no difference: GDIPLIB insists on using window 0!

If anyone who has experience of GDIP can tell me, please, whether I am doing anything wrong or if this is the way it is meant to function, I'll be grateful.
Re: Transparent colours
Post by DDRM on Oct 31st, 2016, 11:30am

Ooh, that's a tricky one, at least for me - you could try running it past Richard.

Having had a quick look at the code for the two libraries, I suspect it might be to do with the device context. The calls in GDIPLIB seem to refer to the @memhdc within each routine, and MULTIWIN sets that to the relevant device context when you select a given window, so it should be OK...

...BUT I see that at the end of PROC_gdipinit there is a call to FN_gdipsetdc.

Possible solutions, which I haven't tried (sorry, I'm busy...):

1) If you select the relevant window BEFORE initialising GDIP, does that solve your problem? Is that an acceptable limitation, or do you need to be able to draw transparencies to multiple windows?

2) Can you include a call to FN_gdipsetdc(@memhdc) after each change of window? Not sure if that will work... you may not be allowed to initialise it more than once.

3) If all else fails (but (1) works), can you shut down and re-initalise GDIPLIB?

Best wishes,

D
Re: Transparent colours
Post by KenDown on Oct 31st, 2016, 11:54am

Hmmm. Thanks for those suggestions.

No, I only need the transparent colours in one window, so I could indeed try selecting it before initialising - something I would never have thought of trying.

I could also try the gdipsetdc call.

Thanks for your help.
Re: Transparent colours
Post by KenDown on Oct 31st, 2016, 12:31pm

Aaaargh!

The first suggestion caused the program to hang-up big time!

INSTALL@lib$+"GDIPLIB"
INSTALL @lib$+"MULTIWINMOD"
PROC_multiwin(2)
PROC_selectwin(2)
PROC_gdipinit
brush%=FN_gdipcreatebrush(&880000FF)

That took the Vulcan nerve pinch to get out of!

It helped if I had created the window before PROCgdipinit etc in that the program didn't hang up, but neither did it make any difference: gdip still wrote to the original window.

Next I tried setting
PROC_selectwin(2)
@hwnd%=!overlay%
@memdc%=FN_hdc(@hwnd%)
R%=FN_gdipsetdc(@memdc%)

where overlay% is the result of FN_createwindow but then gdip refused to work and nothing appeared in any of the windows.

Thanks for your trouble.
Re: Transparent colours
Post by DDRM on Oct 31st, 2016, 4:51pm

Hmmm. You've obviously been playing with your multiwin library, which makes it hard for me to second-guess...

This works for me:
Code:
      INSTALL @lib$+"WINLIB5A"
      INSTALL @lib$+"MULTIWIN"
      INSTALL @lib$+"GDIPLIB"

      MODE 21
      GCOL 2
      RECTANGLE FILL 100,100,600,400
      GCOL 1
      CIRCLE FILL 400,400,200

      PROC_gdipinit
      brush%=FN_gdipcreatebrush(&50F00020)
      DIM x(10),y(10)
      x()=50.0,160.0,280.0,300.0,170.0
      y()=50.0,200.0,200.0,50.0,30.0
      PROC_gdippolygon(brush%, 5, x(), y(),1)
      PROC_gdipdeletebrush(brush%)

      PROC_multiwin(2)
      w1h%=FN_createwin(1,"Extra 1",600,400,200,200,0,&96C00000,0)
      PROC_selectwin(1)

      GCOL 4
      RECTANGLE FILL 50,50,40,40

      t%=FN_gdipsetdc(@memhdc%)
      brush%=FN_gdipcreatebrush(&5000F020)
      PROC_gdippolygon(brush%, 5, x(), y(),1)
      PROC_gdipdeletebrush(brush%)

      PROC_gdipexit

      WAIT 200

      PROC_selectwin(0)
      PROC_closewin(1)
 

If I put the PROC_gdipinit block after the PROC_selectwin(1) (without having had it earlier), it uses GDIP fine in the extra window. Using the code above I can get GDIP drawing in both windows. Can you adapt that for your transparent window?

I don't promise that it isn't generating a resource leak, or something nasty...

D
Re: Transparent colours
Post by KenDown on Oct 31st, 2016, 10:20pm

Amazing!

As you can see, I have created two transparent windows (which is what I wanted) and yes, it does work. The only thing different I can see is that you create the brush and delete it immediately after use.

However unfortunately it doesn't do what I want - the transparent colour is transparent within the window, but not transparent when the window is dragged over the base window. Oh well.

Thanks for your help. I am constantly amazed at the heights of knowledge scaled by some here.

The mod to Multiwin is
cmp eax,&201:jz F%
cmp eax,&203:jz F%
cmp eax,&204:jz F%
where we check for &203. I can't remember why we check but it was suggested to me by someone in this august forum and solved a problem I had.

INSTALL @lib$+"WINLIB5A"
INSTALL @lib$+"MULTIWIN"
INSTALL @lib$+"GDIPLIB"

MODE 21
GCOL 2
RECTANGLE FILL 100,100,600,400
GCOL 1
CIRCLE FILL 400,400,200

PROC_gdipinit
brush%=FN_gdipcreatebrush(&50F00020)
DIM x(10),y(10)
x()=50.0,160.0,280.0,300.0,170.0
y()=50.0,200.0,200.0,50.0,30.0
PROC_gdippolygon(brush%, 5, x(), y(),1)
PROC_gdipdeletebrush(brush%)

PROC_multiwin(2)
w1h%=FNcreatetransparent(1)
w2h%=FNcreatetransparent(2)
PROC_selectwin(2)

GCOL 4
RECTANGLE FILL 50,50,140,140

t%=FN_gdipsetdc(@memhdc%)
brush%=FN_gdipcreatebrush(&66008888)
PROC_gdippolygon(brush%, 5, x(), y(),1)
PROC_gdipdeletebrush(brush%)

PROC_gdipexit

g%=GET

PROC_selectwin(0)
PROC_closewin(1)
PROC_closewin(2)
END
:
DEFFNcreatetransparent(win%):LOCALtrans%
trans%=FN_createwin(win%,"Extra "+STR$win%,600+40*win%,400,400,300,0,&96C00000,0)
PROC_selectwin(win%)
COLOUR3,255,252,162
COLOUR9,255,0,0
VDU26:COLOUR129:CLS
transparent%=TINT(60,160)
SYS"SetWindowLong",trans%,-20,&80000
SYS"SetLayeredWindowAttributes",trans%,transparent%,0,1
VDU5
=trans%

Re: Transparent colours
Post by DDRM on Nov 1st, 2016, 09:07am

Looking at the routine for making a transparent window, I see that you are setting a colour to be rendered as transparent - so it's not surprising that your semi-transparent patch isn't considered transparent, since it no longer has that colour.

I'm guessing, but don't know, that the Windows code for this is like that for "TransparentBlt", which doesn't allow for graded transparency, so you may be on a loser trying to do it this way.

My guess would be that your best option would be to put the contents of your "transparent window" in a 32 bit DIBSection in another device context, and then use AlphaBlend to copy it over your main window.

Best wishes,

D
Re: Transparent colours
Post by KenDown on Nov 1st, 2016, 7:40pm

Clearing the window to a particular colour and then setting that colour as transparent is the way the Help tells me to do it. If there is a better way I'm more than willing to learn it!

I guess what I'm really looking for are translucent, rather than completely transparent, colours.

Anyway, thanks for all your help. I am now a better informed (but probably not more skilful) programmer.