天天看點

SDL2筆記04_使用Cairo在SDL2上畫圖01

  1. 先貼一份github上的代碼

    https://github.com/tsuu32/sdl2-cairo-example

    • 不知道是不是版本問題,有一行編譯會報錯,注釋掉就能跑了
    #include <stdio.h>
     #include <stdbool.h>
     #include <SDL.h>
     #include <cairo/cairo.h>
    
     int
     main(int argc, char *argv[]) {
         SDL_Init(SDL_INIT_VIDEO);
    
         SDL_Window *window = SDL_CreateWindow("An SDL2 window",
                                               SDL_WINDOWPOS_UNDEFINED,
                                               SDL_WINDOWPOS_UNDEFINED,
                                               640,
                                               480,
                                               SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
    
         SDL_Renderer *renderer = SDL_CreateRenderer(window,
                                                     -1,
                                                     SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    
         int window_width;
         int window_height;
         SDL_GetWindowSize(window, &window_width, &window_height);
    
         printf("window_width=%d\n"
                "window_height=%d\n",
                window_width, window_height);
    
         int renderer_width;
         int renderer_height;
         SDL_GetRendererOutputSize(renderer, &renderer_width, &renderer_height);
    
         printf("renderer_width=%d\n"
                "renderer_height=%d\n",
                renderer_width, renderer_height);
    
         int cairo_x_multiplier = renderer_width / window_width;
         int cairo_y_multiplier = renderer_height / window_height;
    
         SDL_Surface *sdl_surface = SDL_CreateRGBSurface(0,
                                                         renderer_width,
                                                         renderer_height,
                                                         32,
                                                         0x00ff0000,
                                                         0x0000ff00,
                                                         0x000000ff,
                                                         0);
    
         printf("sdl_surface->w=%d\n"
                "sdl_surface->h=%d\n"
                "sdl_surface->pitch=%d\n",
                sdl_surface->w, sdl_surface->h, sdl_surface->pitch);
         printf("sdl_surface->format->format=%s\n",
                SDL_GetPixelFormatName(sdl_surface->format->format));
    
         cairo_surface_t *cr_surface = cairo_image_surface_create_for_data((unsigned char *) sdl_surface->pixels,
                                                                           CAIRO_FORMAT_RGB24,
                                                                           sdl_surface->w,
                                                                           sdl_surface->h,
                                                                           sdl_surface->pitch);
         // 找不到定義(可能是版本問題),故注釋掉
         //    cairo_surface_set_device_scale(cr_surface, (double )cairo_x_multiplier, (double )cairo_y_multiplier);
         cairo_t *cr = cairo_create(cr_surface);
    
         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
         SDL_RenderClear(renderer);
    
         // White background with SDL2 API
         // SDL_FillRect(sdl_surface, NULL, SDL_MapRGB(sdl_surface->format, 255, 255, 255));
    
         // White background with cairo API
         cairo_set_source_rgba(cr, 1, 1, 1, 1.0);
         cairo_rectangle(cr, 0, 0, 640, 480);
         cairo_fill(cr);
    
         double xc = 320.0;
         double yc = 240.0;
         double radius = 200.0;
         double angle1 = 45.0 * (M_PI / 180.0);
         double angle2 = 180.0 * (M_PI / 180.0);
    
         cairo_set_source_rgba(cr, 0, 0, 0, 1.0);
         cairo_set_line_width(cr, 10.0);
         cairo_arc(cr, xc, yc, radius, angle1, angle2);
         cairo_stroke(cr);
    
         cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.6);
         cairo_set_line_width(cr, 6.0);
    
         cairo_arc(cr, xc, yc, 10.0, 0, 2 * M_PI);
         cairo_fill(cr);
    
         cairo_arc(cr, xc, yc, radius, angle1, angle1);
         cairo_line_to(cr, xc, yc);
         cairo_arc(cr, xc, yc, radius, angle2, angle2);
         cairo_line_to(cr, xc, yc);
         cairo_stroke(cr);
    
         SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, sdl_surface);
         SDL_FreeSurface(sdl_surface);
    
         SDL_RenderCopy(renderer, texture, NULL, NULL);
         SDL_RenderPresent(renderer);
    
         bool done = false;
         while (!done) {
             SDL_Event event;
             while (SDL_PollEvent(&event)) {
                 switch (event.type) {
                     case SDL_QUIT:
                         done = true;
                         break;
                     default:
                         break;
                 }
             }
             SDL_Delay(100);
         }
    
         cairo_destroy(cr);
         cairo_surface_destroy(cr_surface);
    
         SDL_DestroyTexture(texture);
         SDL_DestroyRenderer(renderer);
         SDL_DestroyWindow(window);
    
         SDL_Quit();
    
         return 0;
     }
               
    • 運作後是這樣的
      SDL2筆記04_使用Cairo在SDL2上畫圖01
  2. 正式開始
    1. 我們使用clion建立c++工程,并引入

      gtk+3.0

      sdl2.0

      • cmakefiles.txt如下
      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)
      add_executable(main ${SOURCE_FILES})
      
      target_link_libraries(main mingw32 SDL2main SDL2 SDL2_image)
      
                 
    2. 把gtk+3需要的dll拷貝到生成.exe的目錄裡
    3. 編寫代碼
      1. SDL_Renderer

        SDL_Texture

        都必須要用

        SDL_TEXTUREACCESS_STREAMING

        來建立
        • 建立sdl_renderer渲染器
        SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1,
               /**SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC |*/
                SDL_TEXTUREACCESS_STREAMING); // 使用STREAMING 流式 建立render
        
                   
        • 建立sdl_texture紋理,必須使用

          SDL_PIXELFORMAT_ARGB8888

          格式
        SDL_Rect textureRect = {0, 0, 640, 480};
        SDL_Rect tmpRect = {100, 100, 100, 100};
        SDL_Texture *sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888,
                                                   SDL_TEXTUREACCESS_STREAMING, // 目前發現隻用Steaming才能顯示
                                                   textureRect.w,
                                                   textureRect.h);
        
                   
      2. cairo

        畫到

        sdl_texture

        上,建立

        cairo_surface_t

        • 使用

          CAIRO_FORMAT_ARGB32

          格式
          void *pixels;
            int pitch = 0;
            SDL_LockTexture(sdlTexture, NULL, &(pixels), &pitch);
            cairo_surface_t *cairo_surface = cairo_image_surface_create_for_data(
                    (unsigned char *) pixels,
                     CAIRO_FORMAT_ARGB32, // 與 SDLSDL_PIXELFORMAT_ARGB8888 對應
                    textureRect.w, textureRect.h, pitch);
            cairo_t *pen = cairo_create(cairo_surface);
            SDL_UnlockTexture(sdlTexture);
                     
      3. 編寫繪圖代碼,這裡從網址上粘貼了一份

        https://cairographics.org/samples/

        連結
      * 畫個扇形
        ```c++
         void drawIt(cairo_t *cr) {
             double xc = 128.0;
             double yc = 128.0;
             double radius = 100.0;
             double angle1 = 45.0 * (M_PI / 180.0);  /* angles are specified */
             double angle2 = 180.0 * (M_PI / 180.0);  /* in radians           */
      
             cairo_set_line_width(cr, 1.0);
             cairo_arc(cr, xc, yc, radius, angle1, angle2);
             cairo_stroke(cr);
      
             /* draw helping lines */
             cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.6);
             cairo_set_line_width(cr, 1.0);
      
             cairo_arc(cr, xc, yc, 10.0, 0, 2 * M_PI);
             cairo_fill(cr);
      
             cairo_arc(cr, xc, yc, radius, angle1, angle1);
             cairo_line_to(cr, xc, yc);
             cairo_arc(cr, xc, yc, radius, angle2, angle2);
             cairo_line_to(cr, xc, yc);
             cairo_stroke(cr);
         }
        ```
                 
      1. 完整的main.cpp代碼如下
        #include <iostream>
            #include "SDL.h"
            #include "SDL_image.h"
            #include "cairo/cairo.h"
        
            void drawIt(cairo_t *pCairo);
        
            // 繪制一條曲線
            void drawBesizer(cairo_t *pen) {
                if (pen) {
                    double x = 100.6, y = 328.0;
                    double x1 = 102.4 + 100, y1 = 130.4,
                            x2 = 153.6 + 240, y2 = 405.6,
                            x3 = 230.4 + 400, y3 = 200;
                    cairo_move_to(pen, x, y);
                    cairo_curve_to(pen, x1, y1, x2, y2, x3, y3);
        
                    cairo_set_line_width(pen, 1);           //設定線寬
                    cairo_set_source_rgb(pen, 1.0, 0.0, 0.0); //設定線顔色
                    cairo_stroke(pen);
                }
            }
        
            // 輸出個hello,中文會亂碼
            void drawText(cairo_t *pen, SDL_Rect &rect) {
                int x = (++rect.x) % rect.w, y = rect.y;
            //    cairo_set_source_rgba(pen, 1, 1, 1, 0.5);
                cairo_set_source_rgba(pen, 255, 255, 255, 1);
                cairo_rectangle(pen, x, y - 20, 50, 20);
                cairo_fill(pen);
            //    cairo_paint (pen);
        
                cairo_move_to(pen, x, y);
                cairo_set_line_width(pen, 1);
                cairo_set_source_rgba(pen, 0, 0, 0, 1);
                cairo_set_font_size(pen, 14);
                cairo_show_text(pen, "hello");
        
                cairo_stroke(pen);
            }
        
            int main(int argc, char *argv[]) {
        
                SDL_Init(SDL_INIT_EVERYTHING);
        
                SDL_Window *sdlWindow = SDL_CreateWindow("sdl_draw_on_texture", 0, 0, 640, 480, SDL_WINDOW_ALWAYS_ON_TOP);
                SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1,
                        /**SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC |*/
                                                                 SDL_TEXTUREACCESS_STREAMING); // 使用STREAMING 流式 建立render
        
                SDL_Rect textureRect = {0, 0, 640, 480};
                SDL_Rect tmpRect = {100, 100, 100, 100};
                SDL_Texture *sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888,
                                                              SDL_TEXTUREACCESS_STREAMING, // 目前發現隻用Steaming才能顯示
                                                            textureRect.w,
                                                            textureRect.h);
        
                void *pixels;
                int pitch = 0;
                SDL_LockTexture(sdlTexture, NULL, &(pixels), &pitch);
                cairo_surface_t *cairo_surface = cairo_image_surface_create_for_data(
                        (unsigned char *) pixels,
                          CAIRO_FORMAT_ARGB32, // 與 SDLSDL_PIXELFORMAT_ARGB8888 對應
                        textureRect.w, textureRect.h, pitch);
                cairo_t *pen = cairo_create(cairo_surface);
                SDL_UnlockTexture(sdlTexture);
        
                SDL_Event event;
                int quit = false, delayMs = 1000 / 24;
        
                while (!quit) {
                    uint32_t startTime = SDL_GetTicks();
                    while (SDL_PollEvent(&event) > 0) {
                        if (event.type == SDL_QUIT) {
                            quit = true;
                        }
                    }
        
                    drawIt(pen);
        
            //        cairo_paint(pen);
            //        drawBesizer(pen);
            //        drawText(pen, tmpRect);
                    SDL_RenderCopy(sdlRenderer, sdlTexture, &textureRect, &textureRect);
                    SDL_RenderPresent(sdlRenderer);
        
                    uint32_t endTime = SDL_GetTicks();
                    if (endTime - startTime < delayMs) {
                        SDL_Log("delay %d\n", delayMs - (endTime - startTime));
                        SDL_Delay(delayMs - (endTime - startTime));
                    }
                }
        
                return 0;
            }
        
            void drawIt(cairo_t *cr) {
                double xc = 128.0;
                double yc = 128.0;
                double radius = 100.0;
                double angle1 = 45.0 * (M_PI / 180.0);  /* angles are specified */
                double angle2 = 180.0 * (M_PI / 180.0);  /* in radians           */
        
                cairo_set_line_width(cr, 1.0);
                cairo_arc(cr, xc, yc, radius, angle1, angle2);
                cairo_stroke(cr);
        
                /* draw helping lines */
                cairo_set_source_rgba(cr, 1, 0.2, 0.2, 0.6);
                cairo_set_line_width(cr, 1.0);
        
                cairo_arc(cr, xc, yc, 10.0, 0, 2 * M_PI);
                cairo_fill(cr);
        
                cairo_arc(cr, xc, yc, radius, angle1, angle1);
                cairo_line_to(cr, xc, yc);
                cairo_arc(cr, xc, yc, radius, angle2, angle2);
                cairo_line_to(cr, xc, yc);
                cairo_stroke(cr);
            }
                   
      2. 運作結果(好像沒有抗鋸齒)
        SDL2筆記04_使用Cairo在SDL2上畫圖01