Thread: Rendering 32-bit images - alpha is ignored

  1. #1
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582

    Rendering 32-bit images - alpha is ignored

    I loaded a TGA image with alpha channel used (32-bit color) but for some reason, the alpha channel is ignored when displaying the image. The normal colors are correct, but areas fully transparent (cannot be seen) are all black and fully visible (as if alpha was 255) and the semitransparent areas have the colors drawn as is, but with the alpha at 255. I made sure I set up the BITMAPINFOHEADER struct properly (32 for the .biBitCount value for one), but that didn't work at all. Each pixel has it's own alpha value. I took a screenshot of the original image and what is being displayed, if that helps to explain.

    See screenshot

    The top window shows my program and the way the image is displayed in it. The bottom is what the original looks like. The checkerboard pattern background indicates transparent areas (for those not familiar with the program). The area in focus is the snow-capped peak with the peak on the furthest left (the short mountain). Note the lack of alpha channel usage in my program for that same area.

    How do I get it so I get the alpha channel to be used rather than ignored.

    Edit: I'm using DrawDibDraw if that helps.
    Last edited by ulillillia; 04-15-2007 at 02:57 AM. Reason: Link mistake and a small note

  2. #2
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    DrawDibDraw does not provide any means for doing transparency, it doesn't do anything too fancy either.

    It is only capable of a simple copy from source to target pixel for pixel.

    If you want transparency then use another method, BitBlt?

  3. #3
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    BitBlt doesn't seem to offer that, by looking at the flags and specifications. There's nothing involving alpha blending or the related that I can see. What do I do to use it to draw the transparent image into the now-working back buffer? I found the AlphaBlend function, but in attempting to use it, I get "unresolved external symbols" and when adding the library, a DLL file, it says that it can't be found (Msimg32.dll). There's no "lib" file mentioned.

  4. #4
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Link with msimg32.lib and use AlphaBlend me thinks.

  5. #5
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Okay, that's resolved, but now comes a new problem, a very weird one. I took another screenshot showing it.

    Here's a screenshot showing the effect (and some of the related code).

    This is the other part of the code, that of the AlphaUsage struct:

    Code:
    AlphaUsage.BlendOp = 0; // using AC_SRC_OVER has the same effect
    AlphaUsage.BlendFlags = 0;
    AlphaUsage.SourceConstantAlpha = 255;
    AlphaUsage.AlphaFormat = AC_SRC_ALPHA;
    The screenshot says a lot about the effects I'm seeing. If I move the window out of the center area, the bluish haze is not there and the "copying" of my test image (my logo as I call it) disappears, but when moved back or while the window remains in the center, this bluish haze and copying effect occur. If I move the logo up more off screen, less of the logo is displayed in the "copy effect". Below the bottom area where the image is to be drawn to, the "copy effect" does not occur, but the blue haze is still present. None of the warnings are related to the area where this is occurring (they occur from each usage of fopen, strcpy, sprintf, and other common C-based functions)).

    Edit: I used "The GIMP" to simulate the effects of what I should be seeing. This is what I should be seeing in the actual window. Of course, the final result will have more detail than this as there's the hills, sky fade, ground, some houses, and text on the black sides in addition to what I have so far.
    Last edited by ulillillia; 04-15-2007 at 05:12 AM. Reason: Added simulated screenshot of what I should be seeing

  6. #6
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Maybe the warnings have something to do with your incorrectly using C functions in C++?

    Perhaps some BlendFlags are needed? I have no idea really, GDI is not my thing (even though I do understand it, doesn't mean im that good at it )

  7. #7
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    The documentation says that "BlendFlags" must be zero. I can't get the search box on MSDN's website and any typing I do tends to cause Firefox to use it's quick search feature.

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    AlphaBlend() will do want you want, however it does not support any scaling. What you need to do is make a mask of each of your bitmaps. You then blit them like this:

    Code:
    ...
    if (pImage)
    {
      CBitmap *pPrevMem=(CBitmap *)pTempDC->SelectObject(pMask);
              
      //Perform transparent stretch blit
      m_pMemoryDC->StretchBlt( iX, iY, iTileW, iTileH, pTempDC,
                             0, 0, iOTileW,iOTileH,SRCAND);
                
      pTempDC->SelectObject(pPrevMem);
      pPrevMem=(CBitmap *)pTempDC->SelectObject(pImage);
    
      // Note the use of SRCPAINT rather than SRCCOPY.
      m_pMemoryDC->StretchBlt(iX, iY, iTileW, iTileH, pTempDC,
            0, 0,iOTileW,iOTileH,SRCPAINT);
                   
      pTempDC->SelectObject(pPrevMem);
    }
    ...
    There is a lot of information on the internet concerning this. My PrepareMask() function inside of CTileGDI is nearly straight from CodeGuru's forum example.

    This means you will be blitting two images per bitmap, but it really is the only way to do this if you want scaling support. There is no way to get a pointer to the buffer in GDI so you cannot manually plot pixels without going through the DC's function. This evaluates to 1 function call per pixel and is much slower than just using this method.

    There are a lot of things left unexplained in that code and I cannot possibly explain my entire GDI tile rendering system to you in one post.

    Remember that each DC must have a bitmap or it will not work.

  9. #9
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    Scaling (or stretching as I call it) isn't anything I need. Scaling, to me, is distance and size put in one. Mountains would have high scaling, like 2000, meaning each pixel is 2000 pixels at a scaling value of 1 and something like 60,000 feet distant (depending on the field of view used). I just need a direct draw onto the back buffer. I also happen to know the formula for calculating the resulting color, a formula I've known since 2002 (this is the main version), well before I got into programming.

    You're apparently missing something. As I have it, AlphaBlend is giving weird results. I'm not stretching anything, just drawing the entire image as is at normal size into a location determined by variables (XMain and YMain) my program will change relative to the speed and scaling values used (120 mph and a scaling of 900 would mean the image position changes one pixel every 3/4 second). I just need it to draw the image as is into the back buffer in order of back to front (highest to lowest scaling value), of which BitBlt brings it to the screen buffer.

  10. #10
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Also can I ask why you've chosen MFC over plain Win32 for a game?

  11. #11
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    No, no, no. I'm doing exactly the same. Loading a TGA file type 2 32 bits, and use AlphaBlend to draw it. It just works. You only need this:
    (fragment from my code)
    Code:
    void TGA2_32::draw(HDC hDC, int x, int y, unsigned char alpha)
    {
        if(!this->hBmp) return;
        
        HDC hMemDC = CreateCompatibleDC(hDC);
        SelectObject(hMemDC, this->hBmp);
        BLENDFUNCTION bf;
        bf.AlphaFormat = 1;
        bf.BlendOp = AC_SRC_OVER;
        bf.SourceConstantAlpha = alpha;
        bf.BlendFlags = 0;
        AlphaBlend(hDC, x, y, this->nWidth, this->nHeight, hMemDC, 
                        0, 0, this->nWidth, this->nHeight, bf);
        DeleteDC(hMemDC);
    }
    The "AlphaFormat=1" is only because AC_SRC_ALPHA is not defined in my version of the gdi header, and I found it should be 1.

    What you probably forgot, is doing premultiplying.

    That is, after you loaded the pixel data, you set:
    R to (R*A/255)
    G to (G*A/255)
    B to (B*A/255)

    That is needed for the AlphaBlend function to work correctly.

  12. #12
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    My advice: get rid of your "DrawDibDraw" thing, drawing bitmaps with plain Win32 functions is easy enough.

  13. #13
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    Quote Originally Posted by Bubba View Post
    AlphaBlend() will do want you want, however it does not support any scaling.
    Yes it does. Why anyway do you think it takes two height parameters and two width parameters?

    I tested it, and it scaled/stretched well. The only thing AlphaBlend does not support is mirroring.

  14. #14
    Math wizard
    Join Date
    Dec 2006
    Location
    USA
    Posts
    582
    @zacs7:
    Also can I ask why you've chosen MFC over plain Win32 for a game?
    What do you mean by this? What's the difference? Around November or so, I, at the MSN Newsgroups, was told about using DrawDibDraw as it was the fastest thing that didn't use DirectX. I don't want to use DirectX.

    What's wrong with using DrawDibDraw anyway? For images without alpha, it's worth using, unless you explain what's wrong with using DrawDibDraw.

    I tried premultiplying, but it gives the exact same result as in my screenshot (the haze and the "copy effect"). This is in my LoadFile function:

    Code:
    		while (ArrayIndex < BMPInfo->biSizeImage) // premultiplies the colors for alphablend to work
    		{
    			NewColor = (float)BMPData[ArrayIndex]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex] = (unsigned char)NewColor;
    			NewColor = (float)BMPData[ArrayIndex+1]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex+1] = (unsigned char)NewColor;
    			NewColor = (float)BMPData[ArrayIndex+2]*(float)BMPData[ArrayIndex+3]/255.0+0.5;
    			BMPData[ArrayIndex+2] = (unsigned char)NewColor;
    			ArrayIndex += 4;
    		}
    NewColor is a float. BMPData is an unsigned char. ArrayIndex is an unsigned int (since arrays can't have negative index values). The adding of 0.5 is for rounding purposes. Multiplying 255 by 255 in a char would cause variable overflow and thus the reason for using a float. A short could also work but is less precise. TGAs are read in BGRA order so the loop is doing the blue first referencing the alpha 3 array index values higher. Either way, the result is exactly the same as before.

    Edit: I tried using BitBlt to copy, paint, and invert pixels and wow do I get weird results. From using this in that same area without AlphaBlend or DrawDibDraw (commented out):

    BitBlt(HDCBack, Mountains.XMain, Mountains.YMain, MountainsInfo.biWidth, MountainsInfo.biHeight, HDCScreen, MountainsInfo.biWidth, MountainsInfo.biHeight, SRCCOPY);

    I get what is shown in this screenshot. Could this be due to BitBlt being unable to draw 32-bit or is it because there's something wrong with the data (DrawDibDraw displays it just fine). Premultiplying it yields the exact same scene. SRCPAINT gives a brighter area in the center and SRCINVERT gives a darker area in the center, but is monotonic like this without any resemblance of looking like mountains.

    Edit #2: Another big clue found. I messed around with the BLENDFUNCTION structure and found some other clues. I took some notes and found an interesting, but bizarre, pattern. On black (HTML color 000000), it renders as white (HTML color FFFFFF). On a background of 2060F0 (a bluish color, based on HTML RGB notation rather than BGR), it draws as 40C0FF. Near the bottom part of this, due to the copy effect, it draws as 60FFFF. On a A0A8B0 background, it draws as C0FFFF and for the copy effect, as E0FFFF. The red value seems to be adding 32, the green either doubling or adding 96, and the blue being set to 255 or something else. Strangely enough, that very closely matches the pixel in the top left corner to which the image is to be drawn on (compare 2060FF and 2060F0, strikingly similar). I checked the premultiplication stuff and it makes complete sense. The pixel at 0, 46 (in my image edittor) has the color of (166, 154, 150, 128) in RGBA order. My debug test shows it as 150, 154, 166, and 128 before premultiplication and 75, 77, 83, 128 after it which is exactly what I expected. Why is it doing this? Why isn't any image being displayed? What is with the copying down and to the right anomaly? Only DrawDibDraw actually displays anything in the way of an image, only without the alpha computation.
    Last edited by ulillillia; 04-16-2007 at 01:38 PM. Reason: More useful clues found

  15. #15
    Registered User pronecracker's Avatar
    Join Date
    Oct 2006
    Location
    netherlands
    Posts
    158
    If you want to get it to work, you could first try it with plain Win32 API. I know that that can work correctly and I know exactly the way, so that's why I recommend you to try that first.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 32 bit color depth bitmap problem with XP
    By kalabala in forum C++ Programming
    Replies: 0
    Last Post: 12-22-2008, 06:56 AM
  2. binary numbers
    By watshamacalit in forum C Programming
    Replies: 4
    Last Post: 01-14-2003, 11:06 PM
  3. 16 bit or 32 bit
    By Juganoo in forum C Programming
    Replies: 9
    Last Post: 12-19-2002, 07:24 AM
  4. 32 bit or 16 ???
    By GiraffeMan in forum C Programming
    Replies: 11
    Last Post: 04-24-2002, 12:56 PM
  5. Array of boolean
    By DMaxJ in forum C++ Programming
    Replies: 11
    Last Post: 10-25-2001, 11:45 PM