てけもぐ Tech 忘備録

SDL の簡単なサンプル

対象

SDL初学者

内容

SDL には四角や円を描くそれ用の関数はないので、それ用のコードを防備録として載せておきます。
デモはこちら

main.cpp:


#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include <SDL3/SDL.h>
#include <cmath>
#include <iostream>

constexpr int WINDOW_WIDTH = 300;
constexpr int WINDOW_HEIGHT = 300;
SDL_Renderer *renderer = nullptr;
SDL_Window *window = nullptr;

void drawBox(float x, float y) {
    SDL_FColor color = {0.5f, 0.5f, 0.5f, 1.0};
    SDL_FPoint tex = {0.0f, 0.0f};
    float len = 100.0f;

    SDL_Vertex box[4] = {
        {{x, y}, color, tex},
        {{x + len, y}, color, tex},
        {{x + len, y + len}, color, tex},
        {{x, y + len}, color, tex},
    };

    int indice[6] = {0};
    for (int i = 0; i < 2; i++) {
        indice[i * 3] = i * 2;
        indice[i * 3 + 1] = i * 2 + 1;
        indice[i * 3 + 2] = (i * 2 + 2) % 4;
    }

    SDL_RenderGeometry(renderer, NULL, box, 4, indice, 6);
}

void drawCircle(float x, float y) {
    constexpr int segment = 32;

    float radius = 50.0f;
    SDL_FColor color = {0.5f, 0.5f, 0.5f, 1.0};

    SDL_Vertex vec[segment + 1];
    vec[0].position = {x, y};
    vec[0].color = color;
    vec[0].tex_coord = {0.0f, 0.0f};

    for (int i = 0; i < segment; i++) {
        float angle = i * 2 * SDL_PI_F / (segment);
        vec[i + 1].position = {x + radius * cosf(angle),
                               y + radius * sinf(angle)};
        vec[i + 1].color = color;
        vec[i + 1].tex_coord = vec[0].tex_coord;
    }
    int indice[segment * 3];
    for (int i = 0; i < segment; i++) {
        indice[i * 3 + 0] = 0;
        indice[i * 3 + 1] = i + 1;
        indice[i * 3 + 2] = (i + 1) % segment + 1;
    }

    SDL_RenderGeometry(renderer, NULL, vec, segment + 1, indice, segment * 3);
}

void main_loop() {
    SDL_RenderClear(renderer);
    drawBox(50, 50);
    drawCircle(200, 200);
    SDL_RenderPresent(renderer);
}

int main(int argc, char *argv[]) {

    if (!SDL_Init(SDL_INIT_VIDEO)) {
        std::cerr << "Failed to initiate SDL3" << SDL_GetError() << "\n";
        return 1;
    }

    window = SDL_CreateWindow("Sample", WINDOW_WIDTH, WINDOW_HEIGHT,
                              SDL_WINDOW_RESIZABLE);

    SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED,
                          SDL_WINDOWPOS_CENTERED);

    renderer = SDL_CreateRenderer(window, nullptr);
    SDL_SetRenderVSync(renderer, 1);

#ifdef __EMSCRIPTEN__
    emscripten_set_main_loop(main_loop, 0, 1);
#else
    bool running = true;
    SDL_Event ev;
    while (running) {
        while (SDL_PollEvent(&ev)) {
            if (ev.type == SDL_EVENT_QUIT) {
                running = false;
            }
        }
        main_loop();
    }
#endif
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

#ifdef __EMSCRIPTEN__
extern "C" {
EMSCRIPTEN_KEEPALIVE
void stop_loop() { emscripten_cancel_main_loop(); }
}
#endif

CMakeList.txt は以下の様に。


cmake_minimum_required(VERSION 3.28)
project(sdlSample LANGUAGES CXX)

if(EMSCRIPTEN)
else()
find_package(SDL3 CONFIG REQUIRED)
endif()

add_executable(${PROJECT_NAME} main.cpp)

if(EMSCRIPTEN)
    target_link_libraries(${PROJECT_NAME} PRIVATE
        "-sUSE_SDL=3"
        "-sMODULARIZE=1"
        "-sEXPORT_NAME=SDLSampleModule"
        "-sENVIRONMENT=web"
        "-sOFFSCREENCANVAS_SUPPORT=1"
        "-sNO_EXIT_RUNTIME=1"
        "-sEXPORTED_FUNCTIONS=['_main','_stop_loop']"
    )
else()
    target_link_libraries(${PROJECT_NAME} PRIVATE
        SDL3::SDL3
    )
endif()

三角形を合わせて描くことになります。上のサンプルの四角形だと2つの三角形を合わせて作るので、頂点は6つになる。

円の場合も三角形を使って描くので、上の場合は segment=32、つまり 32分割の三角形で円を描くことに。細かくするほどきれいな円になりますが、それだけ処理時間がかかる。

Tags