SDL:全屏半透明背景

6
我试图编写一个程序,使整个屏幕都有半透明的背景。经过一些调查,发现SDL是最好的选择。
我已经编写了创建全屏窗口的代码,并且该窗口的背景透明度为100(255中的100),但出于某种原因它只会绘制纯色。我做错了什么?
// 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);

你想使用部分透明度绘制背景,以便在其下面看到其他窗口和桌面吗?我不相信SDL(或任何其他抽象库)能够做到这一点。你需要访问特定于平台的窗口库(例如Windows、Mac/Cocoa、Linux/Xorg)。 - wavemode
2
但是跨平台库可以将对setWindowTransparency方法的调用转换为适合该平台的本地调用。 - brnby
1个回答

13
在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://dev59.com/VIDba4cB1Zd3GeqPEXb5#24118145)
    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://dev59.com/i2865IYBdhLWcg3wIa_M#3970218)
    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;
}

结果:

Transparent sdl window with two squares

解释:

首先创建一个覆盖整个桌面的无边框窗口。选择一种纯色作为遮罩,并将其用作背景色。(在我的情况下,我使用品红色)。然后可以使用Win32 API函数SetLayeredWindowAttributes对遮罩颜色进行键控。

窗口中此颜色的任何部分都将完全透明。其他位于程序后面的窗口可以像正常情况下一样被交互。默认情况下,其他应用程序可以移动到您的无边框窗口的顶部。

如果想让SDL窗口始终置于其他窗口之上,可以在创建窗口时设置SDL_WINDOW_ALWAYS_ON_TOP标志。

另请参阅


谢谢,还有没有办法使矩形区域可以被点击穿透?这样当你点击矩形时,它不会抓取焦点。 - Tomáš Kordoš
我知道这是一个旧评论,但你(或其他有同样问题的人)可能想要看一下实现回调函数以返回SDL_HitTestResult,并使用SDL_SetWindowHitTest使窗口使用它。(https://wiki.libsdl.org/SDL_HitTestResult,https://wiki.libsdl.org/SDL_SetWindowHitTest) - rsethc
谢谢@Stevoisiak,这太棒了 :) - STEEL
嘿@Stevoisiak,我正在使用这种方法使我的窗口全屏和透明,你有任何想法如何使用此方法绘制半透明形状和渲染半透明纹理吗?它似乎将透明度与所选的颜色键混合。 - plex7090

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接