D언어+SDL2로 비사각형 창 만들기

개요


  • SDL_CreateShapedWindowSDL_SetWindowShape 로 비사각형 창 만들기
  • 작성은 할 수 있었지만, 배경의 투과가 일부 잘못되었다 (요조사)

  • D언어+SDL2
  • dmd2.068.0(32bit)+Dub0.9.23
  • SDL2-2.0.3

  • Windows 10 (64 비트)에서만 확인

  • 경위



    SDL2에서는 비사각형(캐릭터나 도형의 형태)의 윈도우를 작성할 수 있다고 들었으므로, 조사해 보았습니다.

    처음 「SDL 비구형」으로 구그 했습니다만, 「SDL2.0의 새로운 기능」의 곳에서 소개되고 있는 정도로,
    정보를 찾을 수 없습니다. (어째서··)

    어쩔 수 없이 일본어 자료를 포기하고, 영어 기사나 Mercurial에 있는 소스 코드SDL_CreateShapedWindowSDL_SetWindowShape 라는 함수가 그렇다는 것을 알았습니다.
    htps : // 우우키.ぃbsdl. 오 RG / SDL
    htps: //hg.ぃbsdl. rg/SDL/후에/704아0b후 cf75/src/ゔぃ로/SDL_샤페. c
    htps: //hg.ぃbsdl. rg/SDL/훗/704아0b후 cf75/에서 st/에서 st샤페. c

    그건 그렇고, SDL은 C 언어 라이브러리이지만 DerelictSDL2라는 바인딩으로 D 언어에서 그대로 사용할 수 있습니다.

    샘플



    프로젝트 배치


  • shapedwindow/
  • image/
  • background.bmp

  • library/
  • SDL.dll

  • souce/
  • app.d

  • dub.json


  • 런타임



    SDL 공식 로부터 아카이브를 취득·전개 후, 상기와 같이 배치한다

    소스 코드



    이쪽을 참고로 했습니다.
    「프로그램으로 고사리 그리기」를 D언어+SDL2+dub로 그리기
    고마워요.

    souce/app.d
    import std.exception;
    import std.string;
    import std.c.string;
    
    import derelict.sdl2.sdl;
    
    /// SDLのロード
    static this()
    {
        DerelictSDL2.load("./library/SDL2.dll");
    }
    
    /// メイン関数
    void main()
    {
        // SDL初期化
        enforceSdl(SDL_Init(SDL_INIT_EVERYTHING) == 0);
        scope(exit) SDL_Quit();
    
        // ウィンドウの生成
        auto window = enforceSdl(SDL_CreateShapedWindow(
                toStringz("SDL_CreateShapedWindow test"),
                SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                640, 480,
                SDL_WINDOW_BORDERLESS));
        scope(exit) SDL_DestroyWindow(window);
    
        // レンダラーの生成
        auto renderer = enforceSdl(SDL_CreateRenderer(window, -1, 0));
        scope(exit) SDL_DestroyRenderer(renderer);
    
        // 背景画像の読み込み
        auto surface = enforceSdl(SDL_LoadBMP(toStringz("./image/background.bmp")));  //<- 背景が緑色の画像
        scope(exit) SDL_FreeSurface(surface);
    
        // 透過色の指定
        SDL_WindowShapeMode mode;
        mode.mode = ShapeModeColorKey;
        mode.parameters.colorKey = SDL_Color(0, Uint8.max, 0, Uint8.max);
    
        auto texture = enforceSdl(SDL_CreateTextureFromSurface(renderer, surface));
        scope(exit) SDL_DestroyTexture(texture);
    
        // 非矩形ウィンドウに設定
        SDL_Rect srcRect;
        enforceSdl(SDL_QueryTexture(texture, null, null, &srcRect.w, &srcRect.h) == 0);
        SDL_SetWindowSize(window, srcRect.w, srcRect.h);
        SDL_SetWindowShape(window, surface, &mode);
        SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
    
        // 描画実行
        enforceSdl(SDL_RenderCopy(renderer, texture, null, null) == 0);
        SDL_RenderPresent(renderer);
    
        // イベントループ
        mainLoop: for (SDL_Event event; SDL_WaitEvent(&event);)
        {
            switch (event.type)
            {
                // ウィンドウクローズで終了
                case SDL_QUIT:
                    break mainLoop;
                // ESCキー押し下げで終了
                case SDL_KEYDOWN:
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                        break mainLoop;
                    break;
                default:
                    break;
            }
        }
    }
    
    /**
     *  SDLのエラーメッセージの取得
     *
     *  Returns:
     *      SDLのエラーメッセージ。エラーが無ければnull。
     */
    string getSdlMessage() @trusted
    {
        if (auto msg = SDL_GetError())
        {
            SDL_ClearError();
            return msg[0 .. strlen(msg)].idup;
        }
        else
        {
            return null;
        }
    }
    
    /**
     *  SDL関数のエラーチェック
     *
     *  Params:
     *      value = SDL関数の戻り値か、エラーチェック結果。
     *  Returns:
     *      エラーが発生していなければvalue。
     *  Throws:
     *      Exception エラーが発生していた場合にスローされる。
     */
    T enforceSdl(T)(T value, string file = __FILE__, size_t line = __LINE__)
    {
        return enforce(value, getSdlMessage(), file, line);
    }
    

    dub.json
    {
        "name": "shapedwindow",
        "targetType": "executable",
        "description": "A non-rectunglar window test written by D language.",
        "dependencies": {
            "derelict-sdl2": "1.2.8"
        }
    }
    

    빌드



    콘솔
    dub
    

    결과



    [before]


    [after]


    비사각형 창을 만들 수 있었습니다만, 배경(녹색)의 일부가 투과되지 않고 보이고 버립니다.
    texture에서 renderer로 복사할 때 확대 축소가 일어나고 있는(?)일지도 모릅니다만, 모릅니다.

    또한 현재 (2015.8.25) SDL 공식으로 배포되고있는 SDL2.0.3에서는 SDL_SetWindowHitTest가 구현되지 않았기 때문에,
    제목 표시줄이 없는 비사각형 창은 마우스 드래그로 이동할 수 없습니다.
    (마우스 이벤트와 SetWindowPosition 로 자전으로 노력하면 할 수 있을지도 모릅니다만)
    다음 SDL2.0.4에서 SDL_SetWindowHitTest구현되는 를 기다리는 것이 무난한 생각이 들었습니다.
    (DerelictSDL2의 해당 의미에서)

    우선 당초 알고 싶었던 것은 확인할 수 있었으므로, 좋다고 합니다. . .

    감상


  • Derelict와 Dub 덕분에 D 언어에서 SDL을 다루는 것은 매우 쉽습니다.
  • 옛 SDL은 게임 전용이라는 인상이었지만, 최근에는 여러가지 할 수 있는 것이 늘고 있는 모습.
  • 파일을 취급하는 CUI인 어플리에, 간단한 GUI 프런트 엔드를 씌워 배포··같은 것도 해 보고 싶다.
  • 개인적으로는 SDL이 D언어의 표준 라이브러리에 원한다.
  • 좋은 웹페이지 즐겨찾기