SDL2笔记05_SDL2透明背景窗口_windows10_使用sdl_texture绘图

  1. 本节课学习使用SDL2封装一个透明背景的window,并在window上使用SDL_Renderer和SDL_Texture进行绘图
    1. 圆形没有反走样
    2. 计算机几何算法B站有个孔令德老师讲课挺好的,建议看看
      (我只看了两节课,后面工作不忙了再认真看,图论与网络流还没开始看,把SDL和GTK大致学一下再去看把,档期可能要排到明年才能开始看了)

  1. 在windows上要想让SDL_Window和linux不太一样(linux可以直接读取css设置)

    1. 经过多次google终于在这个网址找到了做法http://5.9.10.113/67609916/fully-transparent-window-with-opaque-elements-in-sdl-2链接

    2. 以下为代码网址上copy的代码

      展开查看
       
      
            #include <stdio.h>
            #include <SDL.h>
            #include <SDL_image.h>
            #include <SDL_syswm.h>
            #include <iostream>
            #include <Windows.h>
            #include <string>
      
            SDL_Window *window;
            SDL_Renderer *renderer;
      
            SDL_Texture *image;
            int imageWidth = 0;
            int imageHeight = 0;
      
            bool init() {
                //Initialize SDL
                if (SDL_Init(SDL_INIT_VIDEO) != 0) {
                    printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
                    return false;
                }
      
                //Set texture filtering to linear
                if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
                    printf("Warning: Linear texture filtering not enabled!");
                }
      
                //Create window
                window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 500, 300,
                                             SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS);
                if (window == NULL) {
                    printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
                    return false;
                }
      
                //Create renderer for window
                renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
                if (renderer == NULL) {
                    printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
                    return false;
                }
      
                //Initialize renderer color
                SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
      
                //Initialize PNG loading
                int imgFlags = IMG_INIT_PNG;
                if (!(IMG_Init(imgFlags) & imgFlags)) {
                    printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
                    return false;
                }
                return true;
            }
      
            bool loadImage(const std::string &path) {
                //The final texture
                SDL_Texture *newImage = NULL;
      
                //Load image at specified path
                SDL_Surface *loadedSurface = IMG_Load(path.c_str());
                if (!loadedSurface) {
                    printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
                    return false;
                }
      
                //Create texture from surface pixels
                newImage = SDL_CreateTextureFromSurface(renderer, loadedSurface);
                if (!newImage) {
                    printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
                    return false;
                }
      
                imageWidth = loadedSurface->w;
                imageHeight = loadedSurface->h;
      
                //Get rid of old loaded surface
                SDL_FreeSurface(loadedSurface);
      
                image = newImage;
                return true;
            }
      
      
            void displayImage() {
                SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
                SDL_RenderClear(renderer);
      
                SDL_SetWindowSize(window, imageWidth, imageHeight);
                SDL_Rect renderQuad = {0, 0, imageWidth, imageHeight};
      
                SDL_RenderCopy(renderer, image, NULL, &renderQuad);
                SDL_RenderPresent(renderer);
            }
      
      
            // Makes a window transparent by setting a transparency color.
            bool windowColorKey(SDL_Window *window, COLORREF colorKey) {
      
                SDL_SysWMinfo wmInfo;
                SDL_VERSION(&wmInfo.version);  // Initialize wmInfo
                SDL_GetWindowWMInfo(window, &wmInfo);
                HWND hWnd = wmInfo.info.win.window;
      
                // Change window type to layered
                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 *args[]) {
      
                // Initialize SDL: Create a window and renderer
                init();
      
                // Load the image 
                loadImage("example.png");
      
                // Color key the background of the window (magenta)
                windowColorKey(window, RGB(255, 0, 255));
      
                // Render the image on the widnow with magenta for backround color
                displayImage();
      
                // Check for events
                bool windowActive = true;
                SDL_Event event;
                while (windowActive) {
                    while (SDL_PollEvent(&event) != 0) {
                        if (event.type == SDL_QUIT || event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { windowActive = false; }
                    }
                }
      
                return 0;
            }
      

    3. 观察到应该是windowColorKey()函数起了作用,于是把这段代码提取封装一下

       // Makes a window transparent by setting a transparency color.
       bool windowColorKey(SDL_Window *window, COLORREF colorKey) {
      
           SDL_SysWMinfo wmInfo;
           SDL_VERSION(&wmInfo.version);  // Initialize wmInfo
           SDL_GetWindowWMInfo(window, &wmInfo);
           HWND hWnd = wmInfo.info.win.window;
      
           // Change window type to layered
           SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
      
           // Set transparency color
           return SetLayeredWindowAttributes(hWnd, colorKey, 0, LWA_COLORKEY);
       }
      
  2. 封装TransparentWindow.hpp,实现全透明窗口

        //
        // Created by majiao on 2021/8/22.
        //
    
        #ifndef MAIN_TRANSPARENTWINDOW_HPP
        #define MAIN_TRANSPARENTWINDOW_HPP
    
    
        #include <SDL.h>
        #include <SDL_syswm.h>
        #include <SDL_video.h>
        #include <windows.h>
        #include <cairo.h>
        #include <cmath>
        #include "stdlib.h"
    
    
        class TransparentWindow {
        public:
            SDL_Window *window;
            SDL_Renderer *renderer;
            SDL_Surface *winSurface;
            SDL_Texture *texture;
            SDL_Event event;
    
            SDL_Rect rectRect = {0, 0, 50, 50};
            SDL_Rect backRect = {0};
            SDL_Rect mRect = {SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480};
            SDL_SysWMinfo info;
            HWND hwnd;
    
            COLORREF defaultTransparentColor = RGB(255, 0, 255);
    
            cairo_t *pen;
            void *pixels;
            int pitch = 0;
    
            TransparentWindow() {
                init();
            }
    
            // 欲将SDL_Window背景透明 colorKey需传入RGB(255, 0, 255)
            // Makes a window transparent by setting a transparency color.
            bool windowColorKey(SDL_Window *window, COLORREF colorKey) {
                SDL_SysWMinfo wmInfo;
                SDL_VERSION(&wmInfo.version);  // Initialize wmInfo
                SDL_GetWindowWMInfo(window, &wmInfo);
                HWND hWnd = wmInfo.info.win.window;
    
                // Change window type to layered
                SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
    
                // Set transparency color
                return SetLayeredWindowAttributes(hWnd, colorKey, 0, LWA_COLORKEY);
            }
    
            void init() {
                //Set texture filtering to linear 抗锯齿(平滑效果)
                if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) {
                    printf("Warning: Linear texture filtering not enabled!");
                }
    
                //Create window
                window = SDL_CreateWindow("SDL Tutorial", mRect.x, mRect.y, mRect.w, mRect.h,
                                           SDL_WINDOW_SHOWN /**| SDL_WINDOW_BORDERLESS 取消sdl_window边框*/);
                if (window == NULL) {
                    printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
                    return;
                }
    
                // Create renderer for window
                renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
                if (renderer == NULL) {
                    printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
                    return;
                }
    
                this->windowColorKey(this->window, this->defaultTransparentColor);
    
    
                this->texture = SDL_CreateTexture(this->renderer, SDL_PIXELFORMAT_RGBA8888, /**SDL_TEXTUREACCESS_TARGET |*/
                                                   SDL_TEXTUREACCESS_STREAMING,
                                                  this->mRect.w, this->mRect.h);
                this->pen = initCairoPen(this->pixels, this->pitch);
                draw();
            }
    
            // 这里使用cairo画图没有显示出效果,后面查一下原因
            cairo_t *initCairoPen(void *&pixels, int &pitch) const {
                SDL_LockTexture(texture, NULL, &(pixels), &pitch);
                cairo_surface_t *cairo_surface = cairo_image_surface_create_for_data(
                        (unsigned char *) pixels,
                         CAIRO_FORMAT_ARGB32, // 与 SDLSDL_PIXELFORMAT_ARGB8888 对应
                        mRect.w, mRect.h, pitch);
                cairo_t *tpen = cairo_create(cairo_surface);
                cairo_set_line_width(tpen, 10);
                cairo_set_source_rgba(tpen, 0.6, 0.6, 0.6, 0.6);
                SDL_UnlockTexture(texture);
                return tpen;
            }
    
            void draw() {
                SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
                SDL_RenderClear(renderer);
                // 绘图逻辑
                drawRectAndCircle();
                // 更新texture
                reDrawTexture();
            }
    
            void drawRectAndCircle() {
                // 画一个圆在中心,和一个移动的矩形,并把圆心和矩形4点连线
                rectRect.x++;
                rectRect.x %= mRect.w;
    
                SDL_SetRenderDrawColor(renderer, 255, 0, 0, 0);
                SDL_RenderDrawRect(renderer, &rectRect);
    
                int circleX = mRect.w / 2, circleY = mRect.h / 2;
                drawCircle(renderer, circleX, circleY, 30);
                SDL_RenderDrawLine(renderer, circleX, circleY, rectRect.x, rectRect.y);
                SDL_RenderDrawLine(renderer, circleX, circleY, rectRect.x + rectRect.w, rectRect.y);
                SDL_RenderDrawLine(renderer, circleX, circleY, rectRect.x + rectRect.w, rectRect.y + rectRect.h);
                SDL_RenderDrawLine(renderer, circleX, circleY, rectRect.x, rectRect.y + rectRect.h);
            }
    
            void reDrawTexture() const {
                SDL_RenderCopy(renderer, texture, &mRect, &rectRect);
                SDL_RenderPresent(renderer);
            }
    
            // 不知道从哪里抄下来的画圆算法
            void drawCircle(SDL_Renderer *renderer, int32_t centreX, int32_t centreY, int32_t radius) {
                const int32_t diameter = (radius * 2);
    
                int32_t x = (radius - 1);
                int32_t y = 0;
                int32_t tx = 1;
                int32_t ty = 1;
                int32_t error = (tx - diameter);
    
                while (x >= y) {
                    //  Each of the following renders an octant of the circle
                    SDL_RenderDrawPoint(renderer, centreX + x, centreY - y);
                    SDL_RenderDrawPoint(renderer, centreX + x, centreY + y);
                    SDL_RenderDrawPoint(renderer, centreX - x, centreY - y);
                    SDL_RenderDrawPoint(renderer, centreX - x, centreY + y);
                    SDL_RenderDrawPoint(renderer, centreX + y, centreY - x);
                    SDL_RenderDrawPoint(renderer, centreX + y, centreY + x);
                    SDL_RenderDrawPoint(renderer, centreX - y, centreY - x);
                    SDL_RenderDrawPoint(renderer, centreX - y, centreY + x);
    
                    if (error <= 0) {
                        ++y;
                        error += ty;
                        ty += 2;
                    }
    
                    if (error > 0) {
                        --x;
                        tx += 2;
                        error += (tx - diameter);
                    }
                }
            }
        };
    
        #endif //MAIN_TRANSPARENTWINDOW_HPP
    
  3. main.cpp里就很简单了

    
     #include <stdio.h>
     #include <SDL.h>
     #include <SDL_image.h>
     #include <SDL_syswm.h>
     #include <iostream>
     #include <Windows.h>
     #include <string>
     #include "TransparentWindow.hpp"
    
     int main(int argc, char *args[]) {
         bool windowActive = true;
         SDL_Event event;
         // 创建一个背景透明的窗口
         TransparentWindow win;
         while (windowActive) {
             while (SDL_PollEvent(&event) != 0) {
                 if (event.type == SDL_QUIT || event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { windowActive = false; }
                 SDL_Log("event.type=%d    \n", event.type);
             }
             // 绘图
             win.draw();
             SDL_Delay(1000/60);
         }
    
         return 0;
     }
    
  4. 运行结果如下,由于是透明的,所以就看到了背后的代码

  5. 备忘,项目本地硬盘地址为G:\Xubuntu_Work_Space\From_Xubuntu\codeTest_2019_2_21\SDL2\win\clionWorkspace\study04_window_transparent_01_texture_draw_rect_and_circle

posted @ 2021-08-22 16:21  马角的逆袭  阅读(419)  评论(0编辑  收藏  举报