SDL2笔记06_SDL2透明背景窗口_win10_使用cairo和sdl_texture在透明背景上绘制(偏色)
这篇git提供了简单的
cairo
绘制到sdlTexture上的方法https://gist.github.com/sprae/607305450c51ccc482b78bdadadb9af6
链接配置
makefile
cmake_minimum_required(VERSION 3.19) project(main) set(SDL2_DIR G:/Xubuntu_Work_Space/From_Xubuntu/codeTest_2019_2_21/SDL2/win/SDL2-devel-2.0.14-mingw/SDL2-2.0.14/x86_64-w64-mingw32) set(SDL2_IMAGE_DIR G:/Xubuntu_Work_Space/From_Xubuntu/codeTest_2019_2_21/SDL2/win/SDL2_image-devel-2.0.5-mingw/SDL2_image-2.0.5/x86_64-w64-mingw32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lmingw32") set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") # GTK3的include include_directories( H:/mysoft/clion/clionWorkSpace/gtk+364/include H:/mysoft/clion/clionWorkSpace/gtk+364/include/gtk-3.0 H:/mysoft/clion/clionWorkSpace/gtk+364/include/cairo H:/mysoft/clion/clionWorkSpace/gtk+364/include/gdk H:/mysoft/clion/clionWorkSpace/gtk+364/include/glib-2.0 H:/mysoft/clion/clionWorkSpace/gtk+364/include/pango-1.0 H:/mysoft/clion/clionWorkSpace/gtk+364/include/atk-1.0 H:/mysoft/clion/clionWorkSpace/gtk+364/include/gdk-pixbuf-2.0 H:/mysoft/clion/clionWorkSpace/gtk+364/lib/glib-2.0/include H:/mysoft/clion/clionWorkSpace/gtk+364/lib/gtk-3.0/include ) # SDL2的include include_directories( ${SDL2_DIR}/include/SDL2 ${SDL2_IMAGE_DIR}/include/SDL2 ) link_directories( ${SDL2_DIR}/lib ${SDL2_IMAGE_DIR}/lib ) link_libraries( H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libatk-1.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libcairo-gobject.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libcairo-script-interpreter.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libcairo.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libcroco-0.6.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libffi.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libfontconfig.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libfreetype.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgailutil-3.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgdk-3.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgdk_pixbuf-2.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgio-2.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libglib-2.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgmodule-2.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgobject-2.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgthread-2.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libgtk-3.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libjasper.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libjpeg.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/liblzma.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpango-1.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpangocairo-1.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpangoft2-1.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpangowin32-1.0.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpixman-1.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpng.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libpng15.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/librsvg-2.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libtiff.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libtiffxx.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libxml2.dll.a H:/mysoft/clion/clionWorkSpace/gtk+364/lib/libz.dll.a ) set(SOURCE_FILES main.cpp TransparentWindow.hpp) add_executable(main ${SOURCE_FILES}) target_link_libraries(main mingw32 SDL2main SDL2 SDL2_image)
第一步:windows将SDL_Window背景设为透明,可直接调用
windowColorKey
代码COLORREF defaultTransparentColor = RGB(255, 0, 255); 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); }
第二步,绑定
cairo
和sdlTexture
,有两种方式可用(缺点:当画笔大小为1的时候颜色不对,不知怎么解决)方式一 : 建立cairo, 建立texture, 在cairo上画图,然后update过去
// 方式一 : 建立cairo, 建立texture, 在cairo上画图,然后update过去 int windowWidth = 640, windowHeight = 480; surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, windowWidth, windowWidth); cr = cairo_create(surface); cairo_set_line_width(cr, 1); // 画个圆角矩形, 发现颜色不对 cairo_set_source_rgba(cr, 1, 0, 0, 1); draw_round_rectangle(cr, 100, 100, 180, 120, 10); cairo_stroke(cr); unsigned char *data = cairo_image_surface_get_data(surface); SDL_Texture *texture; SDL_Rect rect = {.x=0, .y=0, .w=windowWidth, .h=windowHeight}; texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, windowWidth, windowHeight); // 设置texture为混合模式 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); int widthPitch = windowWidth << 2; // 更新过去 SDL_UpdateTexture(texture, &rect, data, widthPitch);
方式二:直接建立
sdlTexture
然后从sdlTexture
的像素数据建立cairo
// 方式二 : 建立texture, 从texture的像素数据建立cairo, 直接画到texture上去 // 可能比方式一快, 我没读过cairo_image_surface_create_for_data的源码,不敢妄下定论 SDL_Texture *texture; SDL_Rect rect = {.x=0, .y=0, .w=640, .h=480}; texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, rect.w, rect.h); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); void *pixel; int pitch = 4*rect.w; // 一行的像素字节 ARGB32=4 byte, w = 640 SDL_LockTexture(texture, &rect, &pixel, &pitch); surface = cairo_image_surface_create_for_data( (unsigned char*) pixel, CAIRO_FORMAT_ARGB32, rect.w, rect.h, pitch ); SDL_UnlockTexture(texture); cr = cairo_create(surface); cairo_set_line_width(cr, 10); cairo_set_source_rgb(cr, 255, 0, 0); draw_round_rectangle(cr, 100, 100, 50, 60, 10); cairo_stroke(cr);
完整代码
#include <SDL.h> #include <cairo.h> #include <SDL_syswm.h> #include "windows.h" COLORREF defaultTransparentColor = RGB(255, 0, 255); 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); } static void draw_round_rectangle(cairo_t *cr, double x, double y, double width, double height, double r) { cairo_move_to(cr, x + r, y); cairo_line_to(cr, x + width - r, y); cairo_move_to(cr, x + width, y + r); cairo_line_to(cr, x + width, y + height - r); cairo_move_to(cr, x + width - r, y + height); cairo_line_to(cr, x + r, y + height); cairo_move_to(cr, x, y + height - r); cairo_line_to(cr, x, y + r); cairo_arc(cr, x + r, y + r, r, M_PI, 3 * M_PI / 2.0); cairo_arc(cr, x + width - r, y + r, r, 3 * M_PI / 2, 2 * M_PI); cairo_arc(cr, x + width - r, y + height - r, r, 0, M_PI / 2); cairo_arc(cr, x + r, y + height - r, r, M_PI / 2, M_PI); } int main(int argc, char *argv[]) { SDL_Init(SDL_INIT_VIDEO); SDL_Window *window; SDL_Renderer *renderer; SDL_CreateWindowAndRenderer(640, 480, SDL_WINDOW_ALWAYS_ON_TOP, &window, &renderer); windowColorKey(window, defaultTransparentColor); SDL_SetWindowTitle(window, "Cairo test"); cairo_surface_t *surface; cairo_t *cr; #if 1 // 方式一 : 建立cairo, 建立texture, 在cairo上画图,然后update过去 int windowWidth = 640, windowHeight = 480; surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, windowWidth, windowWidth); cr = cairo_create(surface); cairo_set_line_width(cr, 1); // 画个圆角矩形, 发现颜色不对 cairo_set_source_rgba(cr, 1, 0, 0, 1); draw_round_rectangle(cr, 100, 100, 180, 120, 10); cairo_stroke(cr); unsigned char *data = cairo_image_surface_get_data(surface); SDL_Texture *texture; SDL_Rect rect = {.x=0, .y=0, .w=windowWidth, .h=windowHeight}; texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, windowWidth, windowHeight); // 设置texture为混合模式 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); int widthPitch = windowWidth << 2; // 更新过去 SDL_UpdateTexture(texture, &rect, data, widthPitch); #else // 方式二 : 建立texture, 从texture的像素数据建立cairo, 直接画到texture上去 // 可能比方式一快, 我没读过cairo_image_surface_create_for_data的源码,不敢妄下定论 SDL_Texture *texture; SDL_Rect rect = {.x=0, .y=0, .w=640, .h=480}; texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, rect.w, rect.h); SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); void *pixel; int pitch = 4*rect.w; // 一行的像素字节 ARGB32=4 byte, w = 640 SDL_LockTexture(texture, &rect, &pixel, &pitch); surface = cairo_image_surface_create_for_data( (unsigned char*) pixel, CAIRO_FORMAT_ARGB32, rect.w, rect.h, pitch ); SDL_UnlockTexture(texture); cr = cairo_create(surface); cairo_set_line_width(cr, 10); cairo_set_source_rgb(cr, 255, 0, 0); draw_round_rectangle(cr, 100, 100, 50, 60, 10); cairo_stroke(cr); #endif SDL_Event event; bool is_working = true; while (is_working) { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: SDL_DestroyWindow(window); SDL_DestroyRenderer(renderer); SDL_Quit(); is_working = false; break; } } SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); SDL_Delay(66); } return 0; }
运行截图
SDL2学习笔记 文章被收录于专栏
记录个人笔记