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;
            }
  1. 观察到应该是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

SDL2学习笔记 文章被收录于专栏

记录个人笔记

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务