Win32 GDI: AlphaBlend() not using constant alpha value correctly

老子叫甜甜 提交于 2019-12-11 09:47:38

问题


The code provided at the end draws a grid of red 3x3px rectangles with a random constant alpha value using AlphaBlend(). The output however, turns out not "quite" random:

Notice runs of constant alpha along x-axis.

What might be causing this?

P.S. Stepping though the debugger produces the expected output.


Code to produce output:

void draw_mark(HDC hdc, int x, int y, 
               COLORREF mark_clr, int mark_w, int mark_h, BYTE alpha);

void produce_output(HWND hWnd) {
    InvalidateRect(hWnd, NULL, TRUE);
    UpdateWindow(hWnd);

    const int grid_w = 64, grid_h = 64;
    const int mark_sz = 3;
    HDC hdc = GetDC(hWnd);
    for(int y = 0; y < grid_h; ++y) {
        for(int x = 0; x < grid_w; ++x) {
            BYTE rnd_alpha = rand();    // use random alpha for each mark
            draw_mark(hdc, x * mark_sz, y * mark_sz, 
                      RGB(255,0,0), mark_sz, mark_sz, rnd_alpha);
        }
    }

    // clean-up
    ReleaseDC(hWnd, hdc);
}

// draws a [mark_w x mark_h] rectangle at (x,y) with alpha
void draw_mark(HDC hdc, int x, int y, 
               COLORREF mark_clr, int mark_w, int mark_h, BYTE alpha) 
{
    HDC hdcMem = CreateCompatibleDC(NULL);
    HBITMAP hbm = CreateCompatibleBitmap(hdc, mark_w, mark_h);
    HGDIOBJ hOldBmp = SelectObject(hdcMem, hbm);

    for(int x = 0; x < mark_w; ++x) {
        for(int y = 0; y < mark_h; ++y) {
            SetPixel(hdcMem, x, y, mark_clr);
        }
    }
    POINT marker_center{mark_w / 2, mark_h / 2};
    SetPixel(hdcMem, marker_center.x, marker_center.y, RGB(255, 255, 255));

    BLENDFUNCTION bf{};
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = 0;             // ignore source per-pixel alpha and...
    bf.SourceConstantAlpha = alpha; // ...use constant alpha provided instead

    AlphaBlend(hdc, 
               x - marker_center.x, y - marker_center.y, 
               mark_w, mark_h,  
               hdcMem, 0, 0, mark_w, mark_h, bf);

    // clean-up
    SelectObject(hdcMem, hOldBmp);
    DeleteObject(hbm);
    DeleteDC(hdcMem);
};

EDIT - As I look more into it, here are the additional issues I have noticed:

1- Output is normal when AlphaBlend() destination is a memory DC, but not when a window DC. So the issue has to do with bliting directly to screen.

2- Corrupt output is unrelated to use of rand() function. Replacing BYTE rnd_alpha = rand(); with ++alpha also produces somewhat similar corrupt outputs.

3- More interestingly, suspending the thread in the inner loop such as Sleep(some_duration) seems to reduce the corruption. Higher the some_duration, less the corruption. Here is a sample output:

First output is generated by first blitting to a memory DC, then to window. The rest is directly to the window. Notice how corruption increases(i.e. output becomes less random) as thread suspension time decreases.

来源:https://stackoverflow.com/questions/47056848/win32-gdi-alphablend-not-using-constant-alpha-value-correctly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!