[C/C++] DIB Section with Transparent Background

#1
Hello,
My goal is to use GDI+ for a circular gauge, such as an analog altimeter. In order to do this, I need to use the IMAGE_CREATE_DIBSECTION drawing flag. The problem when using this drawing flag is that the whole rectangular area dedicated to the gauge is drawn black, even if IMAGE_USE_TRANSPARENCY is also used. It means I can not integrate my altimeter in the 2D panel where a circular bezel is drawn...

Does anyone have any clue to solve this problem?

Thanks,
Eric
 
#3
Yes, I knew about this solution, but I don't like it much because it works on FSX Acceleration only. I'd rather have something that works with FSX as well, but maybe I'm asking too much here :)

Eric
 

n4gix

Resource contributor
#4
Well, the actual "clues" might lie with those who responded to Susan's post. The ones who stated that they'd been "doing this for years..." :)

Maybe Jean-Luc's suggested NO_STATIC_BLENDING?
 
#5
As far as I understand, NO_STATIC_BLENDING is not used that way in fs9 as it used to be in fs8. I will test again but I am 99% sure it doesn't do the job. Regarding the people who say they can do transparent gauges for years, they are right, I also did it (see my good old F-16 panel), but these are not vector gauges that use GDI or GDI+ for drawing. This is what I am looking for.

Eric
 
#6
Regarding the people who say they can do transparent gauges for years, they are right, I also did it (see my good old F-16 panel), but these are not vector gauges that use GDI or GDI+ for drawing.
I have used VECTOR gauges in GDI+ with partial transparencies, as in an analog altimeter that has a round background with needles drawn on top of it in GDI+ for years, since the MB339 and the Phantom, which were published by Cloud9 in 2005/2006. As far as I know, nobody else used this method so far, I never had the chance to use it after those two products, since the whole idea of 2D panels today is so old fashined (IMHO)...the way to go for an analog instrument is to draw every moving element in 3D and animate it.

In any case, you just can't do it with SDK alone, not without a some additional helper code.

You need to store the static background image in a memory area in its native pixel format (which, regardless of the source format used, it's *always* 16 bit 1555 or 32 bit 8888) then, at every frame during the _DRAW cycle, restore the background, then draw with GDI+ on top of it.

That's the basic concept, of course I've developed a C++ framework to use it so, I really can't put some source code, since it's really too much intertwined with the rest of framework infrastructure (which basically wraps GDI+ entirely). The key command to put a bitmap on screen as fast as possible in GDI+ is DrawCachedBitmap so, by looking at the GDI+ documentation for that command, you might be able to figure out a solution that works for you.

Don't waste your time trying to find a magical SDK flag that will do this automatically, because there's none, not at least for something that works in FS9 and FSX at the same time, otherwise you could use Susan's example, but that would be FSX/Acceleration or SP2 only.
 
Last edited:
#7
I understand what you're talking about and I will test it ASAP. I understand the concept and I should be able to code this. I agree with you, 2D panels are now out of date, but some people (including myself) still like 2D panels :)

Thanks for your help !!
Eric
 
#8
In my experiments with GDI+ I faced the same issue of missing transparency. I tried to play with rotating compass card and obviously I wanted it to be round.

After digging into FS data structures (namely IMAGE) I examined image buffer ("image" structure member) and found that GDI+ drawing calls simply do not follow FS rule that RGB(0,0,0) color should be transparent and do not set alpha value to 0 where color is black.

Soliution I used was simple. When drawing using GDI+ is complete go through each pixel in drawing buffer and set alpha value to 0 if pixel color is RGB(0,0,0). Doing so requires knowlege of buffer format ("format" structure member) although in all my tests I was geting only IMG_15_BIT format irrespective of FS color settings.

My background static image had the following flags: IMAGE_CREATE_DIBSECTION | IMAGE_USE_TRANSPARENCY | IMAGE_NO_TRANSLATION

Hope this helps.
Sergei.
 
#9
Thank you Sergei, after digging into the problem I came to the same conclusion as you, but I didn't think about your idea. It looks simple and efficient, in my opinion the best way to make it work while keeping good performance.

I just have a question about the IMAGE_NO_TRANSLATION drawing flag, what is it for? Does it mean the color space of the gauge will not be transformed?

Thanks,
Eric
 
#10
Hello Eric,

It looks like IMAGE_NO_TRANSLATION disables any further color space translations of an image making it look the same regardless of time of the day and lighting conditions. During my tests (FS9 and FSXA) I found that it behaves similar to IMAGE_USE_BRIGHT but I cannot confirm that these two flags are absolutely identical.

To be honest I didn't do much testing of this flag. But I remember that I've seen a discussion on Avsim back in 2004 where it was advised to use it together with IMAGE_CREATE_DIBSECTION.

Sergei.
 
#11
Hello Sergei,
I always use IMAGE_USE_BRIGHT with IMAGE_CREATE_DIBSECTION because since now I have been using GDI+ to simulate EFIS screens that are obviously bright whatever the exterior light. As far as I understand, IMAGE_USE_BRIGHT and IMAGE_NO_TRANSLATION are quite similar, not to say the same...

Thanks,
Eric
 
#12
Solution I used was simple. When drawing using GDI+ is complete go through each pixel in drawing buffer and set alpha value to 0 if pixel color is RGB(0,0,0).
This is redundant and will result in an unnecessarily slow down.

although in all my tests I was geting only IMG_15_BIT format irrespective of FS color settings.
As I've said, FS will use two image formats: 1555 or 8888, if IMAGE_USE_ALPHA flag is set.

Have a look at this bit of code, it's part of a C++ class that does many other things, but it should be clear enough what it does:

Code:
GdiCachedBitmap::GdiCachedBitmap( Graphics& g, PELEMENT_STATIC_IMAGE element )
{
	IMAGE* final = element->image_data.final;
	mDimX = final->dim.x;
	mDimY = final->dim.y;
	mID = element->resource_id;

	int stride;
	int pf;
		
	if( final->format == IMG_15_BIT )
	{
		pf = PixelFormat16bppARGB1555;
		stride = 2;
	}
	else if ( final->format == IMG_32_BIT )
	{
		pf = PixelFormat32bppARGB;
		stride = 4;
	}
	else
	{
		throw std::runtime_error("Unknown pixelformat");
	}
	Bitmap bmp(mDimX, mDimY, (mDimX * stride + 3) & ~3, pf, reinterpret_cast<PBYTE>(final->image));
	mCachedBitmap.reset(new CachedBitmap(&bmp, &g));
}
This will be done only once, during PANEL_SERVICE_POST_INSTALL.

At each frame, during PANEL_SERVICE_PRE_DRAW, the DrawCachedBitmap GDI+ function will be called, that will restore the background, in the fastest possible way, since the image has been stored (see the previous CachedBitmap call ) in the native pixel format.
 
Top