Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515

Двойная буферизация для AlphaBlend

30.10.2015, 10:53. Показов 1536. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
При рисовании на "реальном" DC всё просто: перенёс с совместимого DC полупрозрачный прямоугольник, потом ещё один, поверх ещё что-то нарисовал, вот и готово. Но нужно теперь выполнять эти операции в совместимом DC (их будет несколько), и их уже переводить на реальный DC по очереди, сохраняя их альфаканал (через AlphaBlend с AlphaFlag = AC_SRC_ALPHA).
Подобная манипуляция работает с использованием Gdiplus:
1. Создаём Graphics от memDC.
2. Рисуем полупрозрачные примитивы.
3. AlphaBlend(hdc, ... , memDC, ... , bf /*AlphaFlag = AC_SRC_ALPHA*/);
Подобное было сделано лишь для эксперимента.
Пытаюсь сделать подобное на чистом GDI:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//инициализация memDC
...
memDC = CreateCompatibleDC(hdc);
memBM = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
HBITMAP oldBM = (HBITMAP)SelectObject(memDC, memBM);
...
//рисование в memDC
HBRUSH brush = CreateSolidBrush(backColor);
FillAlphaRect(memDC, &rect, brush, backAlpha);
DeleteObject(brush);
HBRUSH oldBr = (HBRUSH)SelectObject(memDC, GetStockObject(NULL_BRUSH));
//прочие операции рисования
SelectObject(memDC, oldBr);
...
//перенос в реальный DC
...
BLENDFUNCTION bf = {
    AC_SRC_OVER,
    0,
    0xff,
    AC_SRC_ALPHA
};
BOOL res = AlphaBlend(
    hdc,
    parentRect.left,
    parentRect.top,
    parentRect.right - parentRect.left,
    parentRect.bottom - parentRect.top,
    memDC,
    rect.left,
    rect.top,
    rect.right - rect.left,
    rect.bottom - rect.top,
    bf);
...
Функция FillAlphaRect:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
BOOL FillAlphaRect(HDC hdc, const RECT* lpcrect, HBRUSH brush, BYTE alpha)
{
    if (alpha > 254) {
        FillRect(hdc, lpcrect, brush);
        return TRUE;
    }
    RECT rect = {
        0,
        0,
        lpcrect->right - lpcrect->left,
        lpcrect->bottom - lpcrect->top
    };
    HDC memDC = CreateCompatibleDC(hdc);
    HBITMAP memBM = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
    memBM = (HBITMAP)SelectObject(memDC, memBM);
    
    FillRect(memDC, &rect, brush);
 
    BLENDFUNCTION bf = {
        AC_SRC_OVER,
        0,
        alpha,
        0
    };
    BOOL res = AlphaBlend(
        hdc,
        lpcrect->left,
        lpcrect->top,
        rect.right,
        rect.bottom,
        memDC,
        0,
        0,
        rect.right,
        rect.bottom,
        bf);
 
    memBM = (HBITMAP)SelectObject(memDC, memBM);
    DeleteDC(memDC);
    DeleteObject(memBM);
    return res;
}
Для работы AlphaBlend с AC_SRC_ALPHA нужно что бы битмап-источник содержал альфа-канал, это работает если вместо FillAlphaRect использовать Graphics::FillRectangle, но как добиться подобного эффекта через AlphaBlend?

Есть ещё идея не заливать прямоугольник и вызывать AlphaBlend, а через CreateDIBSection вручную выставлять цвет и прозрачность.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.10.2015, 10:53
Ответы с готовыми решениями:

Двойная буферизация
Добрый день. Программа должна принимать текст с клавиатуры, выводить его на экран и реагировать на '+' и '-', увеличивая и уменьшая текст...

Двойная буферизация
Добрый день! Имеется обычное оконное приложение Win32, необходимо реализовать при рисовании механизм двойной буферизации. Вот мой код, по...

Двойная буферизация
Написал тетрис (но только с палочками (друг попросил сделать =) )) Писал на чистом WinAPI, в WM_PAINT происходит сначала отрисовка...

2
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
03.11.2015, 12:56  [ТС]
Нашёл такое вот решение:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
BOOL FillAlphaRect(HDC hdc, const RECT* lpcrect, HBRUSH brush, BYTE alpha)
{
    HDC memDC = CreateCompatibleDC(hdc);
 
    RECT rect = {
        0,
        0,
        lpcrect->right - lpcrect->left,
        lpcrect->bottom - lpcrect->top
    };
    BITMAPINFO bmi = { 0 };
    void* pvBits;
 
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = rect.right;
    bmi.bmiHeader.biHeight = rect.bottom;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32; 
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = rect.right * rect.bottom * 4;
 
    HBITMAP memBM = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
    HBITMAP oldBM = (HBITMAP)SelectObject(memDC, memBM);
    FillRect(memDC, &rect, brush);
    for (size_t y = 0; y < rect.bottom; y++)
        for (size_t x = 0; x < rect.right; x++) {
            ((UINT32*)pvBits)[x + y * rect.right] |= 0xff000000;
        }
 
    BLENDFUNCTION bf = {
        AC_SRC_OVER,
        0,
        alpha,
        AC_SRC_ALPHA
    };
    BOOL res = AlphaBlend(
        hdc,
        lpcrect->left,
        lpcrect->top,
        rect.right,
        rect.bottom,
        memDC,
        0,
        0,
        rect.right,
        rect.bottom,
        bf);
 
    (HBITMAP)SelectObject(memDC, oldBM);
    DeleteDC(memDC);
    DeleteObject(memBM);
    return res;
}
правда не знаю, на сколько это оптимально, будет ли это работать быстрее gdiplus?
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
05.11.2015, 15:45  [ТС]
Немного доработал функцию:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
BOOL FillAlphaRect(HDC hdc, const RECT* lpcrect, HBRUSH brush, BYTE alpha)
{
    SIZE_T bmWidth = lpcrect->right - lpcrect->left;
    SIZE_T bmHeight = lpcrect->bottom - lpcrect->top;
    SIZE_T byteCount = bmWidth * bmHeight * 4;
    BITMAPINFO bmi;
    void* pvBits;
 
    //подготовка BITMAPINFO
    ZeroMemory(&bmi, 0);
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = bmWidth;
    bmi.bmiHeader.biHeight = bmHeight;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32; 
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = byteCount;
 
    //контекст в памяти
    HDC memDC = CreateCompatibleDC(hdc);
    //создаём и выбираем битмап нужного размера
    HBITMAP memBM = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
    HBITMAP oldBM = (HBITMAP)SelectObject(memDC, memBM);
 
    //помечаем все пиксили как непрозрачные чёрные (обычный FillRect не задаст старшему байту значение 0xff)
    for (SIZE_T i = 0, size = bmWidth * bmHeight; i < size; ++i)
        ((UINT32*)pvBits)[i] = 0xff000000;
 
    //теперь можно нарисовать что-нибудь (старший байт всех изменённых пикселей обнулится)
    SetBkMode(memDC, GetBkMode(hdc));
    SetBkColor(memDC, GetBkColor(hdc));
    HBRUSH oldBrush = (HBRUSH)SelectObject(memDC, brush);
    HPEN oldPen = (HPEN)SelectObject(memDC, GetStockObject(NULL_PEN));
    //Rectangle вместо FillRect для кистей с несплошной заливкой, например, hatchbrush
    Rectangle(memDC, 0, 0, bmWidth, bmHeight);
    SelectObject(memDC, oldBrush);
    SelectObject(memDC, oldPen);
    //закончили рисовать
 
    //инвертируем старший байт всех пикселей (те что были не тронуты станут полностью прозрачными)
    for (SIZE_T i = 3; i < byteCount; i += 4) 
            ((BYTE*)pvBits)[i] = 0xff - ((BYTE*)pvBits)[i];
 
    //выполняем AlphaBlend с заданным альфа-каналом и форматом AC_SRC_ALPHA
    BLENDFUNCTION bf;
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = alpha;
    bf.AlphaFormat = AC_SRC_ALPHA;
    BOOL res = AlphaBlend(
        hdc,
        lpcrect->left,
        lpcrect->top,
        bmWidth,
        bmHeight,
        memDC,
        0,
        0,
        bmWidth,
        bmHeight,
        bf);
    
    //прибираем за собой
    SelectObject(memDC, oldBM);
    DeleteDC(memDC);
    DeleteObject(memBM);
    return res;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
05.11.2015, 15:45
Помогаю со студенческими работами здесь

Двойная буферизация, мерцание
Всем привет! Пишу просто графическое приложение на чистом WinApi и никак не могу разобраться с двойной буфферизацией. Попробовал...

Двойная буферизация в gdi+
Не могу разобраться, как правильно ее сделать. Есть функция: void createImage(wchar_t *path, int _abscissa, int _ordinate,...

Двойная буферизация графики
Дабы избавиться от мерцания изображения(фоновое изображение + побочные элементы + текс) прибегнул к использованию буферизации, проблема с...

Двойная буферизация не работает
почему то не работает Двойная Буферизация case WM_PAINT: { hdc=BeginPaint(hwnd,&amp;PaintStruct); GetClientRect(hwnd,&amp;rect); ...

Двойная буферизация консоли
У меня есть консольная программа(что-то типа игры) с картой, когда эта карта воспроизводится во время перемещения она мерцает. Не сочтите...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь(не выше 3-го порядка) постоянного тока с элементами R, L, C, k(ключ), U, E, J. Программа находит переходные токи и напряжения на элементах схемы классическим методом(1 и 2 з-ны. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru