SDL: полноэкранный полупрозрачный фон

Я пытаюсь написать программу с полупрозрачным фоном, покрывающим весь экран. После некоторых исследований выяснилось, что SDL будет подходящим вариантом.

Я написал код для создания полноэкранного окна с фоном, альфа которого равна 100 (из 255), но по какой-то причине он просто рисует сплошной цвет. Что я сделал не так?

// Initialise SDL
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
        this->throwSDLError("SDL_Init Error");
}

// Create the window and renderer
if (SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &(this->window), &(this->renderer)) != 0) {
        this->throwSDLError("Could not create the window and renderer");
}

// Set the blend mode to specify how the alpha channel is used
if (SDL_SetRenderDrawBlendMode(this->renderer, SDL_BLENDMODE_BLEND) != 0) {
        this->throwSDLError("Could not set render draw blend mode");
}

// Set the colour to draw
if (SDL_SetRenderDrawColor(this->renderer, 200, 200, 200, 100) != 0) {
        this->throwSDLError("Could not set the drawing colour");
}

// Clear the screen using the colour
if (SDL_RenderClear(this->renderer) != 0) {
        this->throwSDLError("Could not render the screen");
}

// Present the rendered screen
SDL_RenderPresent(this->renderer);

person brnby    schedule 13.04.2014    source источник
comment
Вы хотите нарисовать фон с частичной непрозрачностью, чтобы видеть другие окна и ваш рабочий стол под ним? Я не верю, что SDL (или любая другая библиотека абстракций) сможет это сделать. Вам потребуется доступ к библиотеке окон для конкретной платформы (например, Windows, Mac/Cocoa, Linux/Xorg)   -  person wavemode    schedule 14.04.2014
comment
Но межплатформенная библиотека может преобразовать вызов метода setWindowTransparency в соответствующий собственный вызов для платформы.   -  person brnby    schedule 15.04.2014


Ответы (1)


В Windows вы можете создать прозрачное окно, используя SetLayeredWindowAttributes для цветового кеинга цвета фона из окна SDL без полей.

Код:

// SDL window with transparent background v1.2
#include <SDL.h>
#include <SDL_syswm.h>
#include <Windows.h>

// Makes a window transparent by setting a transparency color.
bool MakeWindowTransparent(SDL_Window* window, COLORREF colorKey) {
    // Get window handle (https://stackoverflow.com/a/24118145/3357935)
    SDL_SysWMinfo wmInfo;
    SDL_VERSION(&wmInfo.version);  // Initialize wmInfo
    SDL_GetWindowWMInfo(window, &wmInfo);
    HWND hWnd = wmInfo.info.win.window;

    // Change window type to layered (https://stackoverflow.com/a/3970218/3357935)
    SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);

    // Set transparency color
    return SetLayeredWindowAttributes(hWnd, colorKey, 0, LWA_COLORKEY);
}

int main(int argc, char** argv) {
    // Get resolution of primary monitor
    int desktopWidth = GetSystemMetrics(SM_CXSCREEN);
    int desktopHeight = GetSystemMetrics(SM_CYSCREEN);

    SDL_Window* window = SDL_CreateWindow("SDL Transparent Window",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        desktopWidth, desktopHeight, SDL_WINDOW_BORDERLESS);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    // Set background color to magenta and clear screen
    SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
    SDL_RenderClear(renderer);

    // Draw blue square in top-left corner
    SDL_Rect rect1 = {0, 0, 100, 100};
    SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
    SDL_RenderFillRect(renderer, &rect1);

    // Draw red square in center of the screen
    SDL_Rect rect2 = {(desktopWidth-100)/2, (desktopHeight-100)/2, 100, 100};
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
    SDL_RenderFillRect(renderer, &rect2);

    // Add window transparency (Magenta will be see-through)
    MakeWindowTransparent(window, RGB(255, 0, 255));

    // Render the square to the screen
    SDL_RenderPresent(renderer);

    // Loop until user quits
    bool quit = false;
    SDL_Event event;
    while (!quit) {
       while (SDL_PollEvent(&event) != 0) {
           if (event.type == SDL_QUIT) {
               quit = true;
           }
       }
    }

    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

Результат:

Прозрачное окно sdl с двумя квадратами

Пояснение:

Сначала создайте окно без полей, которое покрывает весь рабочий стол. Выберите сплошной маскирующий цвет и используйте его в качестве фона. (В моем случае я использовал пурпурный). Затем вы можете отключить маскирующий цвет с помощью функции Win32 API SetLayeredWindowAttributes.

Любая часть окна с этим цветом будет полностью прозрачной. С другими окнами позади вашей программы можно взаимодействовать как обычно. По умолчанию другие приложения можно перемещать поверх окна без полей.

Если вы хотите, чтобы ваше окно SDL всегда было поверх других окон, вы можете установить флаг SDL_WINDOW_ALWAYS_ON_TOP при создании своего окна.

Смотрите также

person Stevoisiak    schedule 21.08.2018
comment
Спасибо, а есть ли способ сделать прямоугольники кликабельными? Поэтому, когда вы нажимаете на прямоугольник, он не захватывает фокус. - person Tomi Kordos; 28.12.2020
comment
Я понимаю, что это старый комментарий, но вы (или другие, пришедшие сюда с тем же вопросом), возможно, захотите взглянуть на реализацию обратного вызова для возврата SDL_HitTestResult и использования SDL_SetWindowHitTest, чтобы окно использовало его. (wiki.libsdl.org/SDL_HitTestResult, wiki.libsdl.org/SDL_SetWindowHitTest) - person rsethc; 13.04.2021
comment
Спасибо @Stevoisiak, это здорово :) - person STEEL; 17.04.2021