目次 - 概要 - SDL 3.0への移行

SDL 3.0への移行

このガイドではアプリケーションをSDL 2.0から3.0に移行するための有益な情報を提供する. APIの変更の詳細は後でヘッダごとにまとめられている.

main()関数はinclude <SDL3/SDL_main.h>をインクルードする必要がある. これはSDL.hには含まれなくなったためである.

関数は以前は負の数でエラーコードを戻したが, bool値を戻すようになった.

このようだったコードは:

    if (SDL_Function() < 0 || SDL_Function() == -1) {
        /* 失敗... */
    }
または
    if (SDL_Function() == 0) {
        /* 成功... */
    }
または
    if (!SDL_Function()) {
        /* 成功... */
    }

このように書き換えなければならない:

    if (SDL_Function()) {
        /* 成功... */
    } else {
        /* 失敗... */
    }

これはSDL_[A-Z]*のようなキャメルケースの関数にのみ適用される. SDL_strcmp()やSDL_memcmp()のような先頭が小文字の関数は, Cのランタイムと合わせるため変更はない.

多くの関数やシンボル名が変更された. SDL2の関数名をSDL3に適合したものに変換するPythonスクリプトrename_symbols.pyが提供されている.

rename_symbols.py --all-symbols source_code_path

より簡単にSDL3へと移行できるセマンティックパッチを当てるSDL_migration.coccを適用することもできる.

SDLヘッダのインクルードは #include <SDL3/SDL.h> のようになった. OpenGLやVulkanを使わない限り必要なSDLヘッダこれのみである.
SDL_image, SDL_mixer, SDL_net, SDL_ttf, SDL_rtfもパスが変更された: 例えばSDL_imageならば #include <SDL3_image/SDL_image.h> である.

SDL2のヘッダをSDL3のものの名前に変換するPythonスクリプトrename_headers.pyが提供されている:

rename_headers.py source_code_path

SDL3では一部のマクロが追加・削除された. これらの置き換えと, 修正箇所に変更内容のコメントを入れるPythonスクリプトrename_macros.pyが提供されている.

rename_macros.py source_code_path

CMakeを使う場合, 以下をプロジェクトに追加すること:

find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
target_link_libraries(mygame PRIVATE SDL3::SDL3)

Autotoolsを使う場合, 以下をプロジェクトに追加すること:

PKG_CHECK_MODULES([SDL3], [sdl3])

そしてCFLAGSに$SDL3_CFLAGSを, LDFLAGSに$SDL3_LIBSを追加すること.

Makefileを使う場合, 以下をプロジェクトに追加すること:

CFLAGS += $(shell pkg-config sdl3 --cflags)
LDFLAGS += $(shell pkg-config sdl3 --libs)

SDL3testライブラリの名称はSDL3_testに変更された.

SDLmainライブラリは削除され, 全てSDL_main.hに置き換えられた.

vi形式のコメントはソースコードから削除された. vimユーザはeditorconfigプラグインで自動的にSDLコーディングスタイルのタブ空白をセットすることができる.

インストールされたSDL CMake configuration ファイルには, SDL3_PREFIX, SDL3_EXEC_PREFIX, SDL3_INCLUDE_DIR, SDL3_INCLUDE_DIRS, SDL3_BINDIR, SDL3_LIBDIRが定義されなくなった. ユーザはSDL3::SDL3, SDL3::SDL3-shared, SDL3::SDL3-static, またはSDL3::HeadersのCMakeジェネレーター式を使用する必要がある. これらの定義をなくすことで, システムSDL3を使う場合でも, ベンダーSDL3を使う場合でも同じように使うことができる.

SDL_atomic.h (アトミック操作)

以下の構造体の名前は次の様に変更された:

以下の関数の名前は次の様に変更された:

SDL_audio.h (再生と録音)

SDL3の音声サブシステムはSDL2とは大きく異なる. コールバックは音声再生の主要な方法ではなくなり, SDL_AudioStreamとデバイスを紐づけるようになった. しかし, 必要ならばコールバックの方法も残されている.

簡略化された音声コールバックインターフェースであるSDL 1.2との互換APIは削除された.

ユーザにとって都合がよいように, SDL3では初期化せずにデバイスをオープンしても暗黙的に音声サブシステムを初期化しないようになった. 必要な時点で明示的にSDL_Init(SDL_INIT_AUDIO)を呼ぶこと.

SDL2は録音デバイスを"capture"デバイス, スピーカーへの再生を"output"デバイスと呼んでいた. SDLでは, 明確にするため用語を"recording"デバイスと"playback"デバイスに改めた.

SDL3音声サブシステムはSDL2よりも強化されている. しかし, 既存のコードを単に移行させたいならば大半は使わなくてもよい. 最も単純なSDLからの移行は次のようになる:

SDL2では音声再生はこのように記述していたが...

    void SDLCALL MyAudioCallback(void *userdata, Uint8 * stream, int len)
    {
        /* 音声の調整を行う. `userdata`を使用する場合もある. 結果を`stream`に書き込む */
    }

    /* ...初期化を行う... */
    SDL_AudioSpec my_desired_audio_format;
    SDL_zero(my_desired_audio_format);
    my_desired_audio_format.format = AUDIO_S16;
    my_desired_audio_format.channels = 2;
    my_desired_audio_format.freq = 44100;
    my_desired_audio_format.samples = 1024;
    my_desired_audio_format.callback = MyAudioCallback;
    my_desired_audio_format.userdata = &my_audio_callback_user_data;
    SDL_AudioDeviceID my_audio_device = SDL_OpenAudioDevice(NULL, 0, &my_desired_audio_format, NULL, 0);
    SDL_PauseAudioDevice(my_audio_device, 0);
SDL3ではこのようになる...
    void SDLCALL MyNewAudioCallback(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount)
    {
        /* 音声の調整を行う. `userdata`を使用する場合もある. 結果を`stream`に書き込む
         *
         * 元からあるコールバックを使いたいならば, このように記述できる:
         */
        if (additional_amount > 0) {
            Uint8 *data = SDL_stack_alloc(Uint8, additional_amount);
            if (data) {
                MyAudioCallback(userdata, data, additional_amount);
                SDL_PutAudioStreamData(stream, data, additional_amount);
                SDL_stack_free(data);
            }
        }
    }

    /* ...初期化を行う... */
    const SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
    SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, MyNewAudioCallback, &my_audio_callback_user_data);
    SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));

SDL2でコールバックの代わりにSDL_QueueAudioを使っていた場合は単純である:

    /* ...初期化を行う... */
    const SDL_AudioSpec spec = { SDL_AUDIO_S16, 2, 44100 };
    SDL_AudioStream *stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
    SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));

    /* ...メインループで... */
    /* buf内の音声の調整を行い, `stream`に追加する */
    SDL_PutAudioStreamData(stream, buf, buflen);
この例は録音にも適用できる. 単純にSDL_PutAudioStreamDataSDL_GetAudioStreamDataに置き換えるだけである.

SDL_AudioInit()SDL_AudioQuit()は削除された. 代わりにSDL_InitSubSystem()SDL_QuitSubSystem()の引数にSDL_INIT_AUDIOを渡すことができる. これはサブシステムの参照カウントを増減させる. 特定の音声ドライバはSDL_AUDIO_DRIVERヒントで選択できる.

SDL_AUDIO_ALLOW_*フラグは削除され, 代わりにオーディオデバイスへの音声形式として要求できるようになったが, 最終的な違いはSDL_AudioStreamが管理する. アプリケーションが「許可」の変更に対応する必要がある場合は, 最終的な形式をSDL_GetAudioDeviceFormat()で得ることができる.

SDL_AudioDeviceIDは, オープンしたオーディオデバイス(「論理」デバイス)と, システムに存在するハードウェアのインスタンスID(「物理」デバイス)の両方を表すようになった. デバイスインスタンスとデバイスのインデックス番号の違いはなくなり, 論理デバイスと物理デバイスはAPIレベルでほぼ同一となった.

デバイスを物理デバイスインスタンスIDでオープンすると, 新しい論理インスタンスIDが生成される. これにより, どのデバイスも複数回オープンできる. このことは互いに無関係なコード片によって起こる可能性がある. SDLは, 複数の論理デバイスを, 背後の物理デバイスへの1つのオーディオストリームとして提供する.

デバイスは, 任意の文字列ではなく, デバイスインスタンスID(またはデフォルトの番号, これはSDL2のNULLと似ている)でオープンする. SDL2のオープンでは, システムデバイスの一覧の文字列と, サウンドサーバのホスト名のような任意の文字列の両方でオープンできた. SDL3では, バックエンドで対応していた多くの任意のデバイス名は時代遅れとなったため廃止され, 残っているものはSDL_hintとデフォルトデバイスIDでオープンすることができる. エンドユーザは環境変数に必要なデバイス名を設定することができるので, アプリケーションはそれに対応する必要はない.

デバイスインデックス番号とiscaptureパラメータを渡された多くの関数は, 単にSDL_AudioDeviceIDを渡されるようになり, 全てのデバイスはユニークになり, 再生デバイスと録音デバイスの一覧のインデックス番号は別になった.

デバイスのインデックス番号を用いてオーディオデバイスを反復処理するのではなく, 新しい関数SDL_GetAudioPlaybackDevices()SDL_GetAudioRecordingDevices()も存在する. これは現在のデバイス一覧を得て, そのインスタンスIDからデバイスの情報を得るものである:

{
    if (SDL_InitSubSystem(SDL_INIT_AUDIO)) {
        int i, num_devices;
        SDL_AudioDeviceID *devices = SDL_GetAudioPlaybackDevices(&num_devices);
        if (devices) {
            for (i = 0; i < num_devices; ++i) {
                SDL_AudioDeviceID instance_id = devices[i];
                SDL_Log("オーディオデバイス %" SDL_PRIu32 ": %s", instance_id, SDL_GetAudioDeviceName(instance_id));
            }
            SDL_free(devices);
        }
        SDL_QuitSubSystem(SDL_INIT_AUDIO);
    }
}

SDL_LockAudioDevice()SDL_UnlockAudioDevice()は削除された. 別スレッドのコールバックを保護する必要がないためである. SDL音声サブシステムとSDL_AudioStreamの内部のロックは存在するため, 音声ストリームはどのスレッドから使っても安全である. アプリケーションがコールバックを特定のストリームに割り当てる場合, 必要ならばSDL_LockAudioStream()でストリームをロックすることができる.

SDL_PauseAudioDevice()は常にデバイスを一時停止するようになり, 第2引数を受けなくなった. 再開する場合は, SDL_ResumeAudioDevice()を使うこと.

SDL_OpenAudioDevice()でオープンしたオーディオデバイスは一時停止状態で開始しないようになった. ストリームと紐づけない限り処理が始まらないためである.

SDL_GetAudioDeviceStatus()は削除され, SDL_AudioDevicePaused()となった.

SDL_QueueAudio()SDL_DequeueAudio(), SDL_ClearQueuedAudio(), SDL_GetQueuedAudioSize()は削除された. SDL_AudioStreamとデバイスの紐づけはこれと同じ機能を持っている.

チャネルを扱うAPIのチャネル番号はUint8だったが, intとなった.

SDL_AudioSpecの機能は縮小され, 形式, チャネル数, サンプリングレートのみを扱うようになった. SDL_AudioSpecから削除されたsilenceメンバ(無音の値)はSDL_GetSilenceValueForFormat()で得ることができる. 削除されたsamplesメンバ(音声バッファの長さ)はSDL3が管理するようになった. デバイスの遅れと処理量を調整したい場合は, 新たにオープンするデバイスのサンプルをSDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMESヒントで強制的に設定できるが, リスクを避けるためデフォルト値から変更すべきではない. 他のSDL2のSDL_AudioSpecメンバは現在では無関係である.

SDL_GetAudioDeviceSpec()は削除された. 代わりにSDL_GetAudioDeviceFormat()を使うこと.

SDL_GetDefaultAudioInfo()は削除された. SDL_GetAudioDeviceFormat()SDL_AUDIO_DEVICE_DEFAULT_PLAYBACKまたはSDL_AUDIO_DEVICE_DEFAULT_RECORDINGを渡すこと. デバイスのオープンには文字列を使用しなくなったため, デフォルトデバイス名を得る手段はなくなった. さらに, SDL3はシステムのデフォルトを変更すると物理デバイス間で即座に移行するため, これをユーザに見せる必要がある場合は, "System default"のような名前を推奨する.

SDL_MixAudioFormat()SDL_MIX_MAXVOLUMEは削除され, 代わりに音声形式と0.0から1.0の間のfloat値を引数とするSDL_MixAudio()が導入された.

SDL_FreeWAV()は削除され, SDL_free()に置き換えられた.

SDL_LoadWAV()は正式な関数で, (関数と同じように使える)マクロではなくなった.

多くのSDLの関数と同様にSDL_LoadWAV_IO()SDL_LoadWAV()はbool値を戻すようになった. SDL_AudioSpecへのポインタは戻さない.

SDL_AudioCVTは削除され, 代わりにSDL_AudioStream(切り出された音声データ)またはSDL_ConvertAudioSamples()関数(一度の呼び出しで音声バッファ上の全てを変換)が使えるようになった.

このようだったコードは:

    SDL_AudioCVT cvt;
    SDL_BuildAudioCVT(&cvt, src_format, src_channels, src_rate, dst_format, dst_channels, dst_rate);
    cvt.len = src_len;
    cvt.buf = (Uint8 *) SDL_malloc(src_len * cvt.len_mult);
    SDL_memcpy(cvt.buf, src_data, src_len);
    SDL_ConvertAudio(&cvt);
    do_something(cvt.buf, cvt.len_cvt);
このように変換する必要がある:
    Uint8 *dst_data = NULL;
    int dst_len = 0;
    const SDL_AudioSpec src_spec = { src_format, src_channels, src_rate };
    const SDL_AudioSpec dst_spec = { dst_format, dst_channels, dst_rate };
    if (!SDL_ConvertAudioSamples(&src_spec, src_data, src_len, &dst_spec, &dst_data, &dst_len)) {
        /* エラー */
    }
    do_something(dst_data, dst_len);
    SDL_free(dst_data);

AUDIO_U16, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U16SYSは削除された. これらはあまり使われず, memsetを用いて1バイトで無音にできなかった. 他の形式を使用すること.

U16音声データに対応するため, 実行時に変換する必要がある場合, 高速に劣化させずに変換できるのはSDL_AUDIO_S16である:

    /* バッファ上で変換する. バッファのサイズは変わらない */
    Sint16 *audio_ui16_to_si16(Uint16 *buffer, const size_t num_samples)
    {
        size_t i;
        const Uint16 *src = buffer;
        Sint16 *dst = (Sint16 *) buffer;

        for (i = 0; i < num_samples; i++) {
            dst[i] = (Sint16) (src[i] ^ 0x8000);
        }

        return dst;
    }

残されていた全てのAUDIO_*の名前は, 一貫性のためSDL_AUDIO_*に変えられた. 値と使い方は同じである.

SDL2では, SDL_AudioStreamは入力されるとき(SDL_AudioStreamPut()で)変換/再サンプリングされた.
SDL3では, 要求があればこれを行う(SDL_GetAudioStreamData()で行う. これはSDL2ではSDL_AudioStreamGet()だった). AudioStreamを使う場合でもほぼ同じだが, 処理の段階が異なるので注意すること.

SDL2では, SDL_AudioStreamAvailable()はNULLを渡すと0を戻した. SDL3では, 他の音声ストリームAPIと合わせるため, SDL_GetAudioStreamAvailable()は-1を戻しエラー文字列を設定する.

SDL2では, SDL_AUDIODEVICEREMOVEDイベントはオープンされたデバイスが取り除かれたときwhichメンバにそのSDL_AudioDeviceIDが設定されて発生したが, 後のバージョンでは, アプリケーションに利用可能なデバイスの一覧の更新を伝えるため, オープンされていないデバイスでもwhichメンバが0で発生した.
SDL3では, このイベントは同じだが, 0ではなく物理デバイスのSDL_AudioDeviceIDが設定されるようになった. この取り除かれた物理デバイスをSDL_OpenAudioDevice()でオープンしていた論理デバイスに対しては, 別にイベントが発生する.

以下の関数の名前は次の様に変更された:

以下の関数は削除された

以下のシンボルの名前は次の様に変更された:

以下のシンボルは削除された:

SDL_cpuinfo.h (CPU仕様の検知)

組み込み関数ヘッダ(mmintrin.h等)は<SDL3/SDL_intrin.h>に移され, 自動的にはSDL.hに含まれなくなった.

SDL_Has3DNow()は削除された. 代わりは存在しない.

SDL_HasRDTSC()は削除された. 代わりは存在しない. 現在はRDTSCオペコードは使用せず, 代わりにSDL_GetPerformanceCounter()SDL_GetPerformanceFrequency()を使うこと.

SDL_SIMDAlloc(), SDL_SIMDRealloc(), SDL_SIMDFree()は削除された. SDL_aligned_alloc(), SDL_aligned_free()SDL_GetSIMDAlignment()と共に使用すると同じことを行うことができる.

以下の関数の名前は次の様に変更された:

SDL_endian.h (バイト順と交換)

以下の関数の名前は次の様に変更された:

SDL_error.h (エラー処理)

以下の関数は削除された:

SDL_events.h (イベント処理)

SDL_PRESSEDとSDL_RELEASEDは削除された. ほとんどの場合, これらを使っている部分はそれぞれ真または偽に置き換えることができる. この値を持つキーボードイベント構造体のstateメンバは, bool型のdownメンバに変更された. 例えば, event.key.stateは, 現在はevent.key.downである.

SDL_Event構造体のtimestampメンバは, SDL_GetTicksNS()で設定されるナノ秒単位となった.

センサーイベントのtimestamp_usメンバの名前はsensor_timestampに変更され, ナノ秒単位となった. この値は可能ならばハードウェアによって設定されるため, SDL_GetTicksNS()で得た値とは恐らく同期しない.

SDL_PushEvent()にイベントを渡す前にevent.common.timestampメンバを設定する必要がある. timestampが0ならば, SDL_GetTicksNS()で値が設定される.

イベントのメモリはSDLが管理するようになった. そのため, SDL_EVENT_DROP_FILEイベントdataは解放してはならない. また, SDL_EVENT_TEXT_EDITINGイベントSDL_EVENT_TEXT_INPUTイベントtextを保持したい場合はコピーしなければならない. SDL_TEXTINPUTEVENT_TEXT_SIZEは不要となったため削除された.

マウスイベントはマウス座標と相対移動量として浮動小数点を使用するようになった. これにより, 環境やディスプレイの拡大縮小によってはサブピクセルを扱えるようになった.

SDL_DISPLAYEVENT_*の各イベントはそれぞれトップレベルのイベントになり, SDL_DISPLAYEVENTは削除された. 一般的にはこの変更により, 初めにSDL_DISPLAYEVENTをチェックしてその後にイベント内容をチェックする代わりに, 単にそれぞれのイベントをチェックするようになる. ディスプレイイベントであるかチェックする必要がある場合は, SDL_EVENT_DISPLAY_FIRST≦type≦SDL_EVENT_DISPLAY_LASTの比較で行える.

SDL_WINDOWEVENT_*の各イベントはそれぞれトップレベルのイベントになり, SDL_WINDOWEVENTは削除された. 一般的にはこの変更により, 初めにSDL_WINDOWEVENTチェックしてその後にイベント内容をチェックする代わりに, 単にそれぞれのイベントをチェックするようになる. ウィンドウイベントであるかチェックする必要がある場合は, SDL_EVENT_WINDOW_FIRST≦type≦SDL_EVENT_WINDOW_LASTの比較で行える.

SDL_SetWindowSize()の結果であってもSDL_EVENT_WINDOW_RESIZEDイベントは常に発生するようになった.

SDL_EVENT_WINDOW_SIZE_CHANGEDは削除された. ウィンドウバッファサイズの変更はSDL_EVENT_WINDOW_PIXEL_SIZE_CHANGEDで検知することができる.

キーボードイベントの, 中間の段階だったkeysymメンバは削除され, symの名前はkeyに変更された.

このようだったコードは:

    SDL_Event event;
    SDL_Keycode key = event.key.keysym.sym;
    SDL_Keymod mod = event.key.keysym.mod;
このように変更する必要がある:
    SDL_Event event;
    SDL_Keycode key = event.key.key;
    SDL_Keymod mod = event.key.mod;

SDL_Eventのゲームパッドイベントのcaxis, cbutton, cdevice, ctouchpad, csensorメンバの名前は, gaxis, gbutton, gdevice, gtouchpad, gsensorに変更された.

SDL_TouchFingerEventのtouchId, fingerIdメンバの名前は, touchID, fingerIDに変更された.

SDL_JoyBatteryEventのlevelメンバは, stateとpercentに分けられた.

SDL_AudioDeviceEventのiscaptureメンバの名前は, recordingに変更された.

SDL_QUERY, SDL_IGNORE, SDL_ENABLE, SDL_DISABLEは削除された. イベント処理状態の設定と確認は, SDL_SetEventEnabled()SDL_EventEnabled()で行える.

SDL_AddEventWatch()は, メモリが足りずにイベント監視コールバックを追加できないときSDL_FALSEを戻すようになった.

SDL_RegisterEvents()は, これ以上ユーザイベントを確保できないとき0を戻すようになった.

SDL_EventFilter()はbool値を戻すようになった.

以下のシンボルの名前は次の様に変更された:

以下のシンボルは削除された:

以下の構造体の名前は次の様に変更された:

以下の関数は削除された:

以下の列挙体の名前は次の様に変更された:

以下の関数の名前は次の様に変更された:

SDL_gamecontroller.h (ゲームコントローラー)

SDL_gamecontroller.hの名前はSDL_gamepad.hになり, 全てのAPIはそれと合った名前に変更された.

SDL_EVENT_GAMEPAD_ADDEDイベントは, イベント構造体gdeviceのwhichメンバにジョイスティックインスタンスIDをセットするようになった.

利用可能なゲームパッドの一覧の内容を直接参照できる関数SDL_GetGamepads(), SDL_GetGamepadNameForID(), SDL_GetGamepadPathForID(), SDL_GetGamepadPlayerIndexForID(), SDL_GetGamepadGUIDForID(), SDL_GetGamepadVendorForID(), SDL_GetGamepadProductForID(), SDL_GetGamepadProductVersionForID(), SDL_GetGamepadTypeForID()が追加された.

ゲームパッドの前面ボタンの名称はA/B/X/YからNorth/South/East/Westに変更され, 特定のハードウェア(XBOXのボタン名)ではなく位置を示すようになった. SDL_GetGamepadButtonLabel()を使えば前面ボタンのラベル名(A/B/X/YやCross/Circle/Square/Triangle)を得ることができる. SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELSヒントは無視され, このヒントを使った変換はボタンの位置に訂正される.
アプリケーションは, 地域や慣れによって異なるため, ユーザにOK/キャンセルボタンとしてのSouth/Eastボタンを入れ替える方法を提供すべきである. これは次のような方法で対応できる:

#define CONFIRM_BUTTON SDL_GAMEPAD_BUTTON_SOUTH
#define CANCEL_BUTTON SDL_GAMEPAD_BUTTON_EAST

bool flipped_buttons;

void InitMappedButtons(SDL_Gamepad *gamepad)
{
    if (!GetFlippedButtonSetting(&flipped_buttons)) {
        if (SDL_GetGamepadButtonLabel(gamepad, SDL_GAMEPAD_BUTTON_SOUTH) == SDL_GAMEPAD_BUTTON_LABEL_B) {
            flipped_buttons = true;
        } else {
            flipped_buttons = false;
        }
    }
}

SDL_GamepadButton GetMappedButton(SDL_GamepadButton button)
{
    if (flipped_buttons) {
        switch (button) {
        case SDL_GAMEPAD_BUTTON_SOUTH:
            return SDL_GAMEPAD_BUTTON_EAST;
        case SDL_GAMEPAD_BUTTON_EAST:
            return SDL_GAMEPAD_BUTTON_SOUTH;
        case SDL_GAMEPAD_BUTTON_WEST:
            return SDL_GAMEPAD_BUTTON_NORTH;
        case SDL_GAMEPAD_BUTTON_NORTH:
            return SDL_GAMEPAD_BUTTON_WEST;
        default:
            break;
        }
    }
    return button;
}

SDL_GamepadButtonLabel GetConfirmActionLabel(SDL_Gamepad *gamepad)
{
    return SDL_GetGamepadButtonLabel(gamepad, GetMappedButton(CONFIRM_BUTTON));
}

SDL_GamepadButtonLabel GetCancelActionLabel(SDL_Gamepad *gamepad)
{
    return SDL_GetGamepadButtonLabel(gamepad, GetMappedButton(CANCEL_BUTTON));
}

void HandleGamepadEvent(SDL_Event *event)
{
    if (event->type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
        switch (GetMappedButton(event->gbutton.button)) {
        case CONFIRM_BUTTON:
            /* OKの場合 */
            break;
        case CANCEL_BUTTON:
            /* キャンセルの場合 */
            break;
        default:
            /* ... */
            break;
        }
    }
}

SDL_GameControllerGetSensorDataWithTimestamp()は削除された. センサーデータのタイムスタンプが必要な場合は, SDL_EVENT_GAMEPAD_SENSOR_UPDATEイベントのsensor_timestampメンバを使うことができる.

SDL_CONTROLLER_TYPE_VIRTUALは削除され, 仮想コントローラーは他のゲームパッドをエミュレートできるようになった. コントローラーが仮想コントローラーであるか知る必要がある場合は, SDL_IsJoystickVirtual()を使うこと.

SDL_CONTROLLER_TYPE_AMAZON_LUNAは削除された. コードはこのように置き換えることができる:

bool SDL_IsJoystickAmazonLunaController(Uint16 vendor_id, Uint16 product_id)
{
    return ((vendor_id == 0x1949 && product_id == 0x0419) ||
            (vendor_id == 0x0171 && product_id == 0x0419));
}

SDL_CONTROLLER_TYPE_GOOGLE_STADIAは削除された. コードはこのように置き換えることができる:

bool SDL_IsJoystickGoogleStadiaController(Uint16 vendor_id, Uint16 product_id)
{
    return (vendor_id == 0x18d1 && product_id == 0x9400);
}

SDL_CONTROLLER_TYPE_NVIDIA_SHIELDは削除された. コードはこのように置き換えることができる:

bool SDL_IsJoystickNVIDIASHIELDController(Uint16 vendor_id, Uint16 product_id)
{
    return (vendor_id == 0x0955 && (product_id == 0x7210 || product_id == 0x7214));
}

SDL_GamepadBindingのinputTypeメンバとoutputTypeメンバの名前はinput_typeとoutput_typeに変更された.

SDL_GetGamepadTouchpadFinger()の指状態は, Uint8型ポインタからbool型ポインタに変更された.

以下の列挙体の名前は次の様に変更された:

以下の構造体の名前は次の様に変更された:

以下の関数の名前は次の様に変更された:

以下の関数は削除された:

以下のシンボルの名前は次の様に変更された:

SDL_gesture.h (ジェスチャ)

ジェスチャAPIは削除された. SDL3の代わりの計画もない. しかし, SDL2のコードはシングルヘッダライブラリに移され, これをSDL2またはSDL3のプログラムに組み込むことができるので, この機能を引き続き提供し移行することができる. これはSDL_gesture GitHubリポジトリにある.

SDL_guid.h (GUID)

SDL_GUIDToString()はGUIDを表す文字列への定数ポインタを戻すようになった.

以下の関数の名前は次の様に変更された:

SDL_haptic.h (ハプティック)

ゲームパッドの単純な振動はSDLハプティックインターフェースからなくなった. 代わりにSDL_RumbleGamepad()を使用すること.

デバイスのインデックス番号を用いてハプティックデバイスを反復処理するのではなく, 新しい関数SDL_GetHaptics()で現在のハプティックデバイスの一覧を得て, そのインスタンスIDから新しい関数でハプティックデバイスの情報を得ることもできる:

{
    if (SDL_InitSubSystem(SDL_INIT_HAPTIC)) {
        int i, num_haptics;
        SDL_HapticID *haptics = SDL_GetHaptics(&num_haptics);
        if (haptics) {
            for (i = 0; i < num_haptics; ++i) {
                SDL_HapticID instance_id = haptics[i];
                SDL_Log("ハプティック %" SDL_PRIu32 ": %s", instance_id, SDL_GetHapticNameForID(instance_id));
            }
            SDL_free(haptics);
        }
        SDL_QuitSubSystem(SDL_INIT_HAPTIC);
    }
}

SDL_GetHapticEffectStatus()はintの代わりにboolを戻すようになった. この関数を呼ぶ前にSDL_GetHapticFeatures()を呼んでエフェクトが対応していること確認する必要がある.

以下の関数の名前は次の様に変更された:

以下の関数は削除された:

SDL_hints.h (ヒント)

SDL_GetHint()でヒント名を指定して呼んだとき, ヒントコールバックは変更前の値ではなく変更後の値を戻すようになった. 変更前の値もヒントコールバックの引数として渡される.

環境変数SDL_VIDEODRIVERとSDL_AUDIODRIVERの名前はSDL_VIDEO_DRIVERとSDL_AUDIO_DRIVERに変更された. しかし, フォールバックとして古い名前にも対応している.

環境変数SDL_VIDEO_X11_WMCLASSとSDL_VIDEO_WAYLAND_WMCLASSは削除され, SDL_SetAppMetadata()のappindentifier引数, またはSDL_SetAppMetadataProperty()のSDL_PROP_APP_METADATA_IDENTIFIER_STRINGの設定に置き換えられた.

環境変数AUDIODEVはOSSとNetBSDのオーディオドライバのオーディオデバイスの場合のみ使用されるようになった. ALSAドライバの場合はSDL_HINT_AUDIO_ALSA_DEFAULT_DEVICEヒントに, sndioドライバの場合は環境変数AUDIODEVICEに置き換えられた.

以下のヒントの名前は次の様に変更された:

以下のヒントは削除された:

以下の環境変数の名前は次の様に変更された:

以下の環境変数は削除された:

以下の関数は削除された:

以下の関数の名前は次の様に変更された:

SDL_init.h (初期化)

Haiku OSで, SDLはSDL_Init()でカレントワークディレクトリに実行ファイルのパスを設定しないようになった. この機能が必要な場合は, 最も簡単な方法はSDL_Initを呼んだ後に次のコードを追加することである:

{
    const char *path = SDL_GetBasePath();
    if (path) {
        chdir(path);
    }
}

以下のシンボルの名前は次の様に変更された:

以下のシンボルは削除された:

SDL_joystick.h (ジョイスティック)

SDL_JoystickIDはSint32からUint32に変更され, 不正なIDは0になった.

デバイスのインデックス番号を用いてジョイスティックを反復処理するのではなく, 新しい関数SDL_GetJoysticks()で現在のジョイスティック一覧を得て, そのインスタンスIDから新しい関数を使ってジョイスティックの情報を得ることもできる:

{
    if (SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
        int i, num_joysticks;
        SDL_JoystickID *joysticks = SDL_GetJoysticks(&num_joysticks);
        if (joysticks) {
            for (i = 0; i < num_joysticks; ++i) {
                SDL_JoystickID instance_id = joysticks[i];
                const char *name = SDL_GetJoystickNameForID(instance_id);
                const char *path = SDL_GetJoystickPathForID(instance_id);

                SDL_Log("ジョイスティック %" SDL_PRIu32 ": %s%s%s VID 0x%.4x, PID 0x%.4x",
                        instance_id, name ? name : "不明", path ? ", " : "", path ? path : "", SDL_GetJoystickVendorForID(instance_id), SDL_GetJoystickProductForID(instance_id));
            }
            SDL_free(joysticks);
        }
        SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
    }
}

SDL_EVENT_JOYSTICK_ADDEDイベントは, イベント構造体jdeviceのwhichメンバにジョイスティックインスタンスIDをセットするようになった.

利用可能なジョイスティック一覧から直接参照できる関数SDL_GetJoysticks(), SDL_GetJoystickNameForID(), SDL_GetJoystickPathForID(), SDL_GetJoystickPlayerIndexForID(), SDL_GetJoystickGUIDForID(), SDL_GetJoystickVendorForID(), SDL_GetJoystickProductForID(), SDL_GetJoystickProductVersionForID(), SDL_GetJoystickTypeForID()が追加された.

SDL_AttachVirtualJoystick()はインデックス番号ではなくジョイスティックインスタンスIDを戻すようになり, エラーのとき0を戻すようになった.

SDL_VirtualJoystickDesc構造体はversionにSDL_VIRTUAL_JOYSTICK_DESC_VERSIONを設定するのではなく, SDL_INIT_INTERFACE()で構造体を初期化するようになった.

以下の関数の名前は次の様に変更された:

以下のシンボルの名前は次の様に変更された:

以下の関数は削除された

以下のシンボルは削除された:

以下の構造体の名前は次の様に変更された:

SDL_keyboard.h (キーボード)

テキスト入力はビデオを初期化しても自動的には有効にならなくなった. テキスト入力を受信したい場合はSDL_StartTextInput()を, 終えるときはSDL_StopTextInput()を呼ぶ必要がある. テキスト入力を開始するとインプットメソッドエディタ(IME)が表示され, キー押下/キー離しイベントがスキップされる. よって, アプリケーションがテキスト入力を必要とする場合のみ有効にすること.

テキスト入力状態はウィンドウごとに変更された. SDL_StartTextInput(), SDL_StopTextInput(), SDL_TextInputActive(), SDL_ClearComposition()には全てウィンドウが引数に追加された.

SDL_GetDefaultKeyFromScancode(), SDL_GetKeyFromScancode(), SDL_GetScancodeFromKey()にはSDL_Keymod引数が追加され, 修飾キーの状態に基づいて結果を修正するようになった.

SDL_GetKeyboardState()の戻り値は, Uint8型ポインタからbool型ポインタに変更された.

以下の関数の名前は次の様に変更された:

以下の関数は削除された

以下の構造体は削除された

SDL_keycode.h (キーコード)

SDL_KeycodeはUint32になった. SDL_Keycodeの取りうる値であることを明確にするため, SDLK_*は列挙体から定数となった.

スキャンコードに直接対応付けられたキーコードにあるSDLK_SCANCODE_MASKビットに加えて, 対応するスキャンコードが存在せず, Unicodeの値ではないキーコードであることを表すSDLK_EXTENDED_MASKビットが追加された

以下のシンボルは削除された:

以下のシンボルの名前は次の様に変更された:

SDL_loadso.h (共有オブジェクト読込と関数検索)

共有オブジェクトハンドルはvoid *から不透明型のSDL_SharedObject *となった. これは型安全性のためで, 機能は変わらない.

SDL_LoadFunction()の戻り値はvoid *からSDL_FunctionPointerとなり, 関数の本来の型へのキャストが必要になった. SDL_FUNCTION_POINTER_IS_VOID_POINTERを定義して旧来の動作と同じ動作にすることもできる.

SDL_log.h (ログ処理)

SDL_Log()はSDL_LOG_PRIORITY_INFO以下の場合は接頭辞(prefix)を表示しないようになった. ログの接頭辞はSDL_SetLogPriorityPrefix()で編集できる.

以下のマクロは削除された:

以下の関数の名前は次の様に変更された:

以下のシンボルの名前は次の様に変更された:

SDL_main.h (メイン)

SDL3には静的リンクするlibSDLmainはなくなった. ヘッダのみのライブラリSDL_main.hに代わり, SDL.hには含まれなくなった.

使い方は単純である: ただ標準のint main(int argc, char* argv[])のあるソースファイルに#include <SDL3/SDL_main.h>を追加するだけである. 詳細はdocs/README-main-functions.mdを参照すること.

一部の環境依存エントリーポイント関数は不要のため削除された. 何らかの理由で必要な場合は, 次の置き換えがある:

#define SDL_UIKitRunApp(ARGC, ARGV, MAIN_FUNC)  SDL_RunApp(ARGC, ARGV, MAIN_FUNC, NULL)
#define SDL_GDKRunApp(MAIN_FUNC, RESERVED)  SDL_RunApp(0, NULL, MAIN_FUNC, RESERVED)

以下の関数は削除された:

SDL_messagebox.h (メッセージボックス)

SDL_MessageBoxButtonDatabuttonidフィールドはbuttonIDに変更された.

以下のシンボルの名前は次の様に変更された:

SDL_metal.h (Metalグラフィック)

SDL_Metal_GetDrawableSize()は削除された. SDL_GetWindowSizeInPixels()が代わりとなる.

SDL_mouse.h (マウス)

SDL_ShowCursor()は3つの関数SDL_ShowCursor(), SDL_HideCursor(), SDL_CursorVisible()に分けられた.

SDL_GetMouseState(), SDL_GetGlobalMouseState(), SDL_GetRelativeMouseState(), SDL_WarpMouseInWindow(), SDL_WarpMouseGlobal()は, 環境が対応していればサブピクセルを表すために浮動小数点のマウス位置を使用するようになった.

SDL_SystemCursorの項目名はCSSのマウスカーソル名と合うように変更された.

以下の関数の名前は次の様に変更された:

以下の関数は削除された:

以下のシンボルの名前は次の様に変更された:

SDL_mutex.h (同期プリミティブ)

SDL_MUTEX_MAXWAITは削除された. 無限に待つのではなく, 最大時間でタイムアウトすると誤解されるためである. このシンボルの代わりに-1を関数に渡すこと.

SDL_MUTEX_TIMEDOUTは削除された. 待機する関数は操作が成功すれば真, タイムアウトすれば偽を戻すようになった.

SDL_LockMutex(), SDL_UnlockMutex(), SDL_WaitSemaphore(), SDL_SignalSemaphore(), SDL_WaitCondition(), SDL_SignalCondition(), SDL_BroadcastCondition()の戻り値はvoidとなった. オブジェクトが適切(NULLを含む. この場合はすぐに戻る)ならば, これらの関数は決して失敗しない. オブジェクトが不正か, 別のスレッドのmutexを解除するなど呼び出しが不正ならば, 予測不能な動作となる.

SDL_TryWaitSemaphore(), SDL_WaitSemaphoreTimeout(), SDL_WaitConditionTimeout()は操作が成功すれば真, タイムアウトならば偽を戻すようになった.

以下の関数の名前は次の様に変更された:

以下のシンボルの名前は次の様に変更された:

SDL_pixels.h (ピクセル形式と変換)

SDL_PixelFormatの名称はSDL_PixelFormatDetailsに変更され, ピクセルの形式を記述するのみで, パレットは含まれなくなった.

SDL_PixelFormatEnumの名称はSDL_PixelFormatに変更され, Uint32の代わりに列挙体の値でピクセル形式を参照するAPI関数で使用されるようになった.

SDL_MapRGB(), SDL_MapRGBA(), SDL_GetRGB(), SDL_GetRGBA()は, オプションとしてパレットを取るようになった.

このようなコードは:

    SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a);

このように変更する必要がある:

    SDL_GetRGBA(pixel, SDL_GetPixelFormatDetails(surface->format), SDL_GetSurfacePalette(surface), &r, &g, &b, &a);

このようなコードは:

    pixel = SDL_MapRGBA(surface->format, r, g, b, a);

このように変更する必要がある:

    pixel = SDL_MapSurfaceRGBA(surface, r, g, b, a);

SDL_CalculateGammaRamp()は削除された. SDL_SetWindowGammaRamp()と同様に, 現在のOSでは十分に対応していないためである. (SDL_video.hを参照すること)

以下の関数の名前は次の様に変更された:

以下のシンボルの名前は次の様に変更された:

以下の関数は削除された:

以下のマクロは削除された:

以下の構造体の名前は次の様に変更された:

SDL_platform.h (環境検知)

環境プリプロセッサマクロの名称は次のように変更された:

SDL2SDL3
__3DS__SDL_PLATFORM_3DS
__AIX__SDL_PLATFORM_AIX
__ANDROID__SDL_PLATFORM_ANDROID
__APPLE__SDL_PLATFORM_APPLE
__BSDI__SDL_PLATFORM_BSDI
__CYGWIN_SDL_PLATFORM_CYGWIN
__EMSCRIPTEN__SDL_PLATFORM_EMSCRIPTEN
__FREEBSD__SDL_PLATFORM_FREEBSD
__GDK__SDL_PLATFORM_GDK
__HAIKU__SDL_PLATFORM_HAIKU
__HPUX__SDL_PLATFORM_HPUX
__IPHONEOS__SDL_PLATFORM_IOS
__IRIX__SDL_PLATFORM_IRIX
__LINUX__SDL_PLATFORM_LINUX
__MACOSX__SDL_PLATFORM_MACOS
__NETBSD__SDL_PLATFORM_NETBSD
__OPENBSD__SDL_PLATFORM_OPENBSD
__OS2__SDL_PLATFORM_OS2
__OSF__SDL_PLATFORM_OSF
__PS2__SDL_PLATFORM_PS2
__PSP__SDL_PLATFORM_PSP
__QNXNTO__SDL_PLATFORM_QNXNTO
__RISCOS__SDL_PLATFORM_RISCOS
__SOLARIS__SDL_PLATFORM_SOLARIS
__TVOS__SDL_PLATFORM_TVOS
__unix__SDL_PLATFORM_UNI
__VITA__SDL_PLATFORM_VITA
__WIN32__SDL_PLATFORM_WIN32
__WINGDK__SDL_PLATFORM_WINGDK
__XBOXONE__SDL_PLATFORM_XBOXONE
__XBOXSERIES__SDL_PLATFORM_XBOXSERIES

Pythonスクリプトrename_macros.pyでソースコード上の名称を自動的に変更することもできる.

新しく追加されたマクロSDL_PLATFORM_WINDOWSは, Xbox, GDK等を含む全てのWindows環境で真となる.

以下の環境プリプロセッサマクロは削除された:

SDL_quit.h (終了処理)

SDL_quit.hは完全に削除された. そこにあった唯一のシンボルSDL_QuitRequestedが必要ならば, 以下をアプリケーションに加えること...

    #define SDL_QuitRequested() (SDL_PumpEvents(), (SDL_PeepEvents(NULL,0,SDL_PEEKEVENT,SDL_EVENT_QUIT,SDL_EVENT_QUIT) > 0))
...しかし, このマクロは1つの式で連続して2つの関数を呼び出すやや汚いものである.

以下のマクロは削除された:

SDL_rect.h (領域)

以下の関数の名前は次の様に変更された:

SDL_render.h (2Dレンダリング)

SDL3でも2Dレンダラは常にバッチで行われる. オン・オフを切り替えるトリックはない. これはどのレンダラを選択してもヒントを使用しても無関係である. このことは, SDL3の2Dレンダラを使う全てのアプリケーションは, その環境の低レベルレイヤグラフィックAPIを直接呼んだ後はSDL_FlushRenderer()を呼ぶ必要があることを意味する. こうすることでアプリケーションが直接描画を開始する前に保留中のSDLのレンダリングが確実に完了する.

SDL_GetRenderDriverInfo()は削除された. 報告されるほとんどの情報は推定で, レンダラを生成する前には正確な情報を得られないためである. この関数はしばしばドライバのインデックス番号を得るために使用された. その場合は, forループの中で呼ばれ, "opengl"のようなドライバ名と比較していた. この目的のためにSDL_GetRenderDriver()が追加された. この関数はドライバ名のみを戻す.

SDL_CreateRenderer()の第2引数は整数のインデックス番号ではなくなり, ドライバ名のconst char *となった. もしforループで"opengl"のようなドライバ名のインデックス番号を検索していたならば, これからは直接文字列を渡すことができる. NULLを渡すことはSDL2で-1を渡すことと同じで, SDLがあなたの代わりにドライバを選択する.

SDL_CreateRenderer()のflags引数は削除された. SDL 3.0で同様の機能をどのように得るかは後の項目を参照すること.

SDL_CreateWindowAndRenderer()は第1引数にウィンドウのタイトルを取るようになった.

SDL_GetRendererInfo()は削除された. レンダラの名前はSDL_GetRendererName()で得られ, 他の情報はレンダラのプロパティで得られる.

テクスチャはデフォルトではSDL_SCALEMODE_LINEARで生成される. そして, テクスチャがαチャネルが存在するモードで生成されたとき, デフォルトではSDL_BLENDMODE_BLENDが使われる.

SDL_QueryTexture()は削除された. テクスチャの属性はSDL_PROP_TEXTURE_FORMAT_NUMBER, SDL_PROP_TEXTURE_ACCESS_NUMBER, SDL_PROP_TEXTURE_WIDTH_NUMBER, SDL_PROP_TEXTURE_HEIGHT_NUMBERで得られる. テクスチャのサイズを浮動小数点の値で得るSDL_GetTextureSize()関数が追加された.

マウスイベントとタッチイベントは座標を変換するためにフィルタされなくなった. 代わりに明確にSDL_ConvertEventToRenderCoordinates()を呼んでマップイベント座標をレンダリングビューポイントにマッピングすることができる.

SDL_RenderWindowToLogical()SDL_RenderLogicalToWindow()の名称はSDL_RenderCoordinatesFromWindow()SDL_RenderCoordinatesToWindow()に変更され, どちらの座標も浮動小数点となった.

レンダラーターゲットのビューポート, クリッピング状態, 拡大率は永続的になり, アクティブな間は常に設定が維持されるようになった.

SDL_Vertexは浮動小数点の色指定に変更され, SDR(Standard Dynamic Range)では[0..1]の範囲となった.

SDL_RenderReadPixels()はメモリ上に確保された領域への代入に代わりサーフェイスを戻すようになった.

SDL2のSDL_RenderSetLogicalSize()(現在のSDL_SetRenderLogicalPresentation())は拡大率とビューポート状態を変更していた. SDL3では, 論理サイズから物理サイズへの変換時の表示モードと拡大率・ビューポート状態は分離しているため, アプリケーションはビューポートや拡大率を設定しながら論理サイズを設定することができる.

以下の関数の名前は次の様に変更された:

以下の関数は削除された:

以下の列挙体の名前は次の様に変更された:

以下のシンボルの名前は次の様に変更された:

以下のシンボルは削除された:

SDL_rwops.h (ファイル入出力)

以下のシンボルの名前は次の様に変更された:

SDL_rwops.hの名称はSDL_iostream.hとなった.

SDL_RWopsは不透明構造体となり, 名称がSDL_IOStreamとなった. SDL_IOStreamを生成するSDL3 API(SDL_IOFromFileなど)の名称は変更されたが, SDL2と同様の機能を持つ. しかし, アプリケーションが提供する関数へのポインタでカスタムされたSDL_IOStreamを生成する場合は, 関数へのポインタを渡してSDL_OpenIO()を呼ぶこと. SDL_IOStreamの機能を呼ぶには, 関数へのポインタが内部にあるため, 標準のAPI(SDL_ReadIOなど)を使うこと.

SDL_IOStreamはC++の標準のiostreamクラスとは無関係であり混同しないこと!

SDL_RWopsの関数へのポインタはSDL_IOStreamInterface構造体に分けられた. これはカスタムされたSDL_IOStreamの実装を生成するときSDL_OpenIOに提供される. 全ての関数は, SDL_IOStreamが不透明構造体となったため, 第1引数としてvoid *userdataを取るようになった.

SDL3では, SDL_RWreadSDL_RWwrite(そして読み込み・書き込み関数へのポインタ)は, 名称だけでなく関数シグネチャ(関数定義)も変更された.

以前はstdioのようだったが...

    size_t SDL_RWread(SDL_RWops *context, void *ptr, size_t size, size_t maxnum);
size_t SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t maxnum);

POSIXのようになった:

    size_t SDL_ReadIO(SDL_IOStream *context, void *ptr, size_t size);
    size_t SDL_WriteIO(SDL_IOStream *context, const void *ptr, size_t size);

このように使用していたコードは...

size_t custom_read(void *ptr, size_t size, size_t nitems, SDL_RWops *stream)
{
    return SDL_RWread(stream, ptr, size, nitems);
}

このように変更する必要がある:

size_t custom_read(void *ptr, size_t size, size_t nitems, SDL_IOStream *stream)
{
    if (size > 0 && nitems > 0) {
        return SDL_ReadIO(stream, ptr, size * nitems) / size;
    }
    return 0;
}

SDL_RWops::typeは削除された. これはアプリケーションにとってもSDL内部で使用するとしても全く訳に立たないためである. ストリームの種類を得るためには, 組み込まれた実行を検知するためのSDL_IOStreamのプロパティを調べること.

SDL_IOStreamInterface::closeの実装は, 自身のuserdataの後処理をする必要があるが, 自身でSDL_CloseIOを呼んではならない. 不透明オブジェクトを解放する前に常に->closeされ, SDL_CloseIOが呼ばれることになっている.

SDL_AllocRW(), SDL_FreeRW(), SDL_RWclose(), ->close関数の直接の呼び出しはAPIから削除された. それにより, RWopsのライフサイクルの管理はSDL_OpenIO()SDL_CloseIO()のみで行われるようになった.

SDL_RWFromFPはAPIから削除された. SDLライブラリがアプリケーションとは別のCランタイムを使用する場合に問題が発生するためである.

これは自身のコードに簡単に実装できる:

#include <stdio.h>

typedef struct IOStreamStdioFPData
{
    FILE *fp;
    bool autoclose;
} IOStreamStdioFPData;

static Sint64 SDLCALL stdio_seek(void *userdata, Sint64 offset, int whence)
{
    FILE *fp = ((IOStreamStdioFPData *) userdata)->fp;
    int stdiowhence;

    switch (whence) {
    case SDL_IO_SEEK_SET:
        stdiowhence = SEEK_SET;
        break;
    case SDL_IO_SEEK_CUR:
        stdiowhence = SEEK_CUR;
        break;
    case SDL_IO_SEEK_END:
        stdiowhence = SEEK_END;
        break;
    default:
        SDL_SetError("'whence'の値が不明");
        return -1;
    }

    if (fseek(fp, (fseek_off_t)offset, stdiowhence) == 0) {
        const Sint64 pos = ftell(fp);
        if (pos < 0) {
            SDL_SetError("ストリームのオフセットを得られない");
            return -1;
        }
        return pos;
    }
    SDL_SetError("ストリームをシークできない");
    return -1;
}

static size_t SDLCALL stdio_read(void *userdata, void *ptr, size_t size, SDL_IOStatus *status)
{
    FILE *fp = ((IOStreamStdioFPData *) userdata)->fp;
    const size_t bytes = fread(ptr, 1, size, fp);
    if (bytes == 0 && ferror(fp)) {
        SDL_SetError("ストリームから読み込めない");
    }
    return bytes;
}

static size_t SDLCALL stdio_write(void *userdata, const void *ptr, size_t size, SDL_IOStatus *status)
{
    FILE *fp = ((IOStreamStdioFPData *) userdata)->fp;
    const size_t bytes = fwrite(ptr, 1, size, fp);
    if (bytes == 0 && ferror(fp)) {
        SDL_SetError("ストリームに書き込めない");
    }
    return bytes;
}

static bool SDLCALL stdio_close(void *userdata)
{
    IOStreamStdioData *rwopsdata = (IOStreamStdioData *) userdata;
    bool status = true;
    if (rwopsdata->autoclose) {
        if (fclose(rwopsdata->fp) != 0) {
            SDL_SetError("ストリームを閉じられない");
            status = false;
        }
    }
    return status;
}

SDL_IOStream *SDL_RWFromFP(FILE *fp, bool autoclose)
{
    SDL_IOStreamInterface iface;
    IOStreamStdioFPData *rwopsdata;
    SDL_IOStream *rwops;

    rwopsdata = (IOStreamStdioFPData *) SDL_malloc(sizeof (*rwopsdata));
    if (!rwopsdata) {
        return NULL;
    }

    SDL_INIT_INTERFACE(&iface);
	/* stdio_sizeは存在しない. SDL_GetIOSizeはstdioと同じ方法でエミュレートするためである */
    iface.seek = stdio_seek;
    iface.read = stdio_read;
    iface.write = stdio_write;
    iface.close = stdio_close;

    rwopsdata->fp = fp;
    rwopsdata->autoclose = autoclose;

    rwops = SDL_OpenIO(&iface, rwopsdata);
    if (!rwops) {
        iface.close(rwopsdata);
    }
    return rwops;
}

stdioを背後で使用するためにSDL_IOFromFile()で生成したストリームは, 内部のFILE *を標準のSDL_IOStreamを通して使用できる. アプリケーションはこのポインタを自身の責任で使用することができ, SDLとアプリケーションが同じCランタイムを使用していることを確認する必要がある.

Appleの環境では, SDL_RWFromFile(現在はSDL_IOFromFile)はアプリケーションにバンドルされたリソースディレクトリから読み込もうとせず, 指定されたパスを変更せずに使用するようになった. これらの環境では, SDL_GetBasePath()でリソースディレクトリを見つけることができる.

SDL_ReadU8(), SDL_ReadU16LE(), SDL_ReadU16BE(), SDL_ReadU32LE(), SDL_ReadU32BE(), SDL_ReadU64LE(), SDL_ReadU64BE()は成功のとき真, そうでないとき偽を戻し, 引数として渡したポインタのデータを保持するようになった.

以下の関数の名前は次の様に変更された:

以下の構造体の名前は次の様に変更された:

SDL_scancode.h (キースキャンコード)

以下のシンボルは削除された:

以下のシンボルの名前は次の様に変更された:

SDL_sensor.h (センサー)

SDL_SensorIDはSint32からUint32に変更され, 不正なIDは0になった.

デバイスのインデックス番号を用いてセンサーを反復処理するのではなく, 新たに現在のセンサーの一覧を得る関数SDL_GetSensors()と, そのインスタンスIDからセンサーの情報を得る関数が追加された.

{
    if (SDL_InitSubSystem(SDL_INIT_SENSOR)) {
        int i, num_sensors;
        SDL_SensorID *sensors = SDL_GetSensors(&num_sensors);
        if (sensors) {
            for (i = 0; i < num_sensors; ++i) {
                SDL_Log("センサー %" SDL_PRIu32 ": %s, 種類 %d, 環境依存の種類 %d",
                        sensors[i],
                        SDL_GetSensorNameForID(sensors[i]),
                        SDL_GetSensorTypeForID(sensors[i]),
                        SDL_GetSensorNonPortableTypeForID(sensors[i]));
            }
            SDL_free(sensors);
        }
        SDL_QuitSubSystem(SDL_INIT_SENSOR);
    }
}

SDL_SensorGetDataWithTimestamp()は削除された. センサーデータのタイムスタンプが必要ならば, SDL_EVENT_SENSOR_UPDATEイベントのsensor_timestampメンバを使用すること.

以下の関数の名前は次の様に変更された:

以下の関数は削除された:

SDL_shape.h (非矩形ウィンドウ)

このヘッダは削除され, SDL_video.hに簡略化されたバージョンのAPIのSDL_SetWindowShape()が追加された. test/testshape.cを参照すること.

SDL_stdinc.h (標準ライブラリ)

stdio.hやstdlib.hのような標準Cのヘッダのようなものは含まれなくなった. SDLのCランタイムに含まれたい関数を使う場合は直接プロジェクトにインクルードする必要がある. M_PIはSDL_stdinc.hに定義されなくなった. 代わりに新しいシンボルSDL_PI_D(double型)とSDL_PI_F(float型)を使うことができる.

bool型はboolとして定義され, intのサイズから1バイトとなった.

SDL3では大文字小文字を無視する文字列操作関数に一貫性を持たせた. SDL2では, SDL_strcasecmp()のような関数は, 通常は英語のアルファベットのみ機能し, さらにユーザのロケールによっては英語の場合も機能しないことがあった. SDL3では一貫性を持たせている:

SDL3で使用しているcase-foldingはトルコ語の'I'を正しく処理しないことに注意すること. これはUnicodeでは非常に困難な文字の1つで, これらの関数は使用する自然言語を特定しないため, この問題を無視することにした.

SDL_strtoll(), SDL_strtoull(), SDL_lltoa(), SDL_ulltoa()は, 対応するCランタイムと合わせるため, 64ビットの値の代わりにlong longを使用する.

SDL_setenv()はスレッドセーフではないため名称がSDL_setenv_unsafe()に変更された.

以下のマクロは削除された:

以下の関数の名前は次の様に変更された:

以下の関数は削除された:

以下のシンボルの名前は次の様に変更された:

SDL_surface.h (サーフェイスの生成と単純な描画)

SDL_Surfaceは簡素化され, 内部の詳細は公開された構造ではなくなった.

SDL_Surfaceのformatメンバピクセル形式の列挙体の値となった. ピクセル形式の完全な詳細はSDL_GetPixelFormatDetails(surface->format)で得ることができる. サーフェイスに関連付けられたパレットはSDL_GetSurfacePalette()で得ることができる. クリップ枠はSDL_GetSurfaceClipRect()で得ることができる.

SDL_Surfaceのuserdataメンバはより汎用的なプロパティインターフェースに置き換えられた. これはSDL_GetSurfaceProperties()で問い合わせることができる.

インデックス形式のサーフェイスはデフォルトでパレットを持たないようになった. パレットのないサーフェイスは, サーフェイス間で変換せずにピクセルをコピーする.

このように使用していたコードは...

    SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, 32, 32, 8, SDL_PIXELFORMAT_INDEX8);
    SDL_Palette *palette = surface->format->palette;
    ...

このように変更する必要がある:

    SDL_Surface *surface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_INDEX8);
    SDL_Palette *palette = SDL_CreateSurfacePalette(surface);
    ...

SDL_ConvertSurfaceの未使用だった引数flagsは削除された.

SDL_CreateRGBSurface()SDL_CreateRGBSurfaceWithFormat()は新しい関数SDL_CreateSurface()に統合された. SDL_CreateRGBSurfaceFrom()SDL_CreateRGBSurfaceWithFormatFrom()は新しい関数SDL_CreateSurfaceFrom()に統合され, 引数の順序はSDL_CreateSurface()との一貫性のため変更された.

古い関数は簡単に実装できる:

    SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    {
        return SDL_CreateSurface(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask));
    }

    SDL_Surface *SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, Uint32 format)
    {
        return SDL_CreateSurface(width, height, format);
    }

    SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    {
        return SDL_CreateSurfaceFrom(width, height, SDL_GetPixelFormatForMasks(depth, Rmask, Gmask, Bmask, Amask), pixels, pitch);
    }

    SDL_Surface *SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 format)
    {
        return SDL_CreateSurfaceFrom(width, height, format, pixels, pitch);
    }

しかし, マスクを使用するコードを移行する場合は, 次のうちの1つの形式を想定しているだろう:

    // 様々なマスク(R, G, B, A)と対応したフォーマット:
    0xFF000000 0x00FF0000 0x0000FF00 0x000000FF → SDL_PIXELFORMAT_RGBA8888
    0x00FF0000 0x0000FF00 0x000000FF 0xFF000000 → SDL_PIXELFORMAT_ARGB8888
    0x0000FF00 0x00FF0000 0xFF000000 0x000000FF → SDL_PIXELFORMAT_BGRA8888
    0x000000FF 0x0000FF00 0x00FF0000 0xFF000000 → SDL_PIXELFORMAT_ABGR8888
    0x0000F800 0x000007E0 0x0000001F 0x00000000 → SDL_PIXELFORMAT_RGB565

SDL_BlitSurface()SDL_BlitSurfaceScaled()の引数dstrectはconstになり, 最後にコピーされた領域は代入されないようになった.

拡大率付きのSDL_BlitSurfaceScaled()SDL_BlitSurfaceUncheckedScaled()が追加された.

API関数のピクセル形式のSDL_PixelFormatは, Uint32ではなく列挙体の値となった.

SDL_SetSurfaceColorKey()はbool値でカラーキーの有効無効を設定できるようになった. この引数でRLEアクセラレーションは制御できない. SDL_SetSurfaceRLE()を用いて別に変更する必要がある.

SDL_SetSurfaceRLE()はbool値でRLEアクセラレーションの有効無効を設定できるようになった.

以下の関数の名前は次の様に変更された:

以下のシンボルは削除された:

以下の関数は削除された:

以下のシンボルの名前は次の様に変更された:

SDL_system.h (環境固有の機能)

SDL_WindowsMessageHookはシグネチャ(関数宣言)が変更され, メッセージを変更することができ, 以降のメッセージ処理をブロックできるようになった.

SDL_RequestAndroidPermissionはブロッキング呼び出しではなくなった. 呼び出し側は応答可能になったとき呼び出されるコールバック関数を提供するようになった.

  • SDL_iPhoneSetAnimationCallback()SDL_iPhoneSetEventPump()の名前はそれぞれSDL_SetiOSAnimationCallback()SDL_SetiOSEventPump()に変更された. SDL2ではiPadが登場する前の古いシンボルに新しい名前を与えるためのマクロだったが, 正式な名前のシンボルが唯一の選択肢となった.

    SDL_IsAndroidTV()の名前はSDL_IsTV()に変更され, Android固有ではなくなった. これにより, 例えばApple TVの場合も真を戻すようになった.

    以下の関数は削除された:

    以下の関数の名前は次の様に変更された:

    SDL_syswm.h (環境依存ウィンドウ)

    ヘッダは削除された.

    WindowsとX11のイベントはSDL_SetWindowsMessageHook()SDL_SetX11EventHook()で設定できるコールバックで処理できるようになった.

    以前SDL_GetWindowWMInfo()で得られた情報はウィンドウのプロパティとなった. 例:

        SDL_SysWMinfo info;
        SDL_VERSION(&info.version);
    
    #if defined(__WIN32__)
        HWND hwnd = NULL;
        if (SDL_GetWindowWMInfo(window, &info) && info.subsystem == SDL_SYSWM_WINDOWS) {
            hwnd = info.info.win.window;
        }
        if (hwnd) {
            ...
        }
    #elif defined(__MACOSX__)
        NSWindow *nswindow = NULL;
        if (SDL_GetWindowWMInfo(window, &info) && info.subsystem == SDL_SYSWM_COCOA) {
            nswindow = (__bridge NSWindow *)info.info.cocoa.window;
        }
        if (nswindow) {
            ...
        }
    #elif defined(__LINUX__)
        if (SDL_GetWindowWMInfo(window, &info)) {
            if (info.subsystem == SDL_SYSWM_X11) {
                Display *xdisplay = info.info.x11.display;
                Window xwindow = info.info.x11.window;
                if (xdisplay && xwindow) {
                    ...
                }
            } else if (info.subsystem == SDL_SYSWM_WAYLAND) {
                struct wl_display *display = info.info.wl.display;
                struct wl_surface *surface = info.info.wl.surface;
                if (display && surface) {
                    ...
                }
            }
        }
    #elif defined(__IPHONEOS__)
        UIWindow *uiwindow = NULL;
        if (SDL_GetWindowWMInfo(window, &info) && info.subsystem == SDL_SYSWM_UIKIT) {
            uiwindow = (__bridge UIWindow *)info.info.uikit.window;
        }
        if (uiwindow) {
            GLuint framebuffer = info.info.uikit.framebuffer;
            GLuint colorbuffer = info.info.uikit.colorbuffer;
            GLuint resolveFramebuffer = info.info.uikit.resolveFramebuffer;
            ...
        }
    #endif
    

    これはこのようになる:

    #if defined(SDL_PLATFORM_WIN32)
        HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
        if (hwnd) {
            ...
        }
    #elif defined(SDL_PLATFORM_MACOS)
        NSWindow *nswindow = (__bridge NSWindow *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
        if (nswindow) {
            ...
        }
    #elif defined(SDL_PLATFORM_LINUX)
        if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
            Display *xdisplay = (Display *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
            Window xwindow = (Window)SDL_GetNumberProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
            if (xdisplay && xwindow) {
                ...
            }
        } else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
            struct wl_display *display = (struct wl_display *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
            struct wl_surface *surface = (struct wl_surface *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
            if (display && surface) {
                ...
            }
        }
    #elif defined(SDL_PLATFORM_IOS)
        SDL_PropertiesID props = SDL_GetWindowProperties(window);
        UIWindow *uiwindow = (__bridge UIWindow *)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, NULL);
        if (uiwindow) {
            GLuint framebuffer = (GLuint)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_UIKIT_OPENGL_FRAMEBUFFER_NUMBER, 0);
            GLuint colorbuffer = (GLuint)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_UIKIT_OPENGL_RENDERBUFFER_NUMBER, 0);
            GLuint resolveFramebuffer = (GLuint)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_UIKIT_OPENGL_RESOLVE_FRAMEBUFFER_NUMBER, 0);
            ...
        }
    #endif
    

    SDL_thread.h (スレッド)

    SDL_CreateThreadWithStackSizeSDL_CreateThreadWithPropertiesに置き換えられた.

    SDL_CreateThreadSDL_CreateThreadWithPropertiesは全ての環境でbeginthread/endthread関数へのポインタを取るようになり(ほとんどの場合無視される), 全ての環境でこれを隠すためにマクロで置き換えるようになった. これはソースコードレベルではこれまでと同じだが, 実際に呼ばれる関数のシグネチャ(関数宣言)は変更されている. 実際のライブラリ上のシンボルはSDL_CreateThreadRuntimeである. "SDL_CreateThread"をDLL/共有ライブラリ/Dylibから検索しようとすると失敗する. これを直接呼んではならず, 常にマクロを使用すること!

    SDL_GetTLS(), SDL_SetTLS()はTLS IDへのポインタを取るようになり, 必要ならば自動的にスレッドセーフな方法で初期化するようになった.

    以下の関数の名前は次の様に変更された:

    以下の関数は削除された:

    以下のシンボルの名前は次の様に変更された:

    SDL_timer.h (タイマ)

    SDL_GetTicks()は64ビットの値を戻すようになった. SDL_TICKS_PASSEDマクロを使用せずに直接値を比較できる. 例:

        Uint32 deadline = SDL_GetTicks() + 1000;
        ...
        if (SDL_TICKS_PASSED(SDL_GetTicks(), deadline)) {
            ...
        }
    

    これはこのようになる:

        Uint64 deadline = SDL_GetTicks() + 1000
        ...
        if (SDL_GetTicks() >= deadline) {
            ...
        }
    

    マクロを使いたいならば, 次の様に自分で定義することもできる:

        #define SDL_TICKS_PASSED(A, B)  ((Sint32)((B) - (A)) >= 0)
    

    SDL_AddTimer()に渡すコールバックは引数が次の様に変更された:

        Uint32 SDLCALL TimerCallback(void *userdata, SDL_TimerID timerID, Uint32 interval);
    

    SDL_touch.h (タッチデバイス)

    SDL_GetTouchNameSDL_GetTouchDeviceName()になり, インデックス番号の代わりにSDL_TouchIDを取るようになった.

    SDL_TouchIDSDL_FingerIDはUint32に変更され, 不正な値は0になった.

    インデックス番号を用いてタッチデバイスを反復処理するのではなく, 利用可能なデバイスを得る新しい関数SDL_GetTouchDevices()も存在する.

    インデックス番号を用いてタッチした指を反復処理するのではなく, 現在のアクティブな指を得る新しい関数SDL_GetTouchFingers()も存在する.

    以下の関数は削除された:

    SDL_version.h (バージョン)

    SDL_GetRevisionNumber()はAPIから削除された. これは SDL 2.0では常に0を戻していた.

    SDL_GetVersion()はバージョンを表す値を戻す. この値はSDL_VERSIONNUM()を通して別のバージョンと比較できる.

    以下の構造体は削除された:

    以下のシンボルの名前は次の様に変更された:

    SDL_video.h (ディスプレイとウィンドウ)

    一部のビデオバックエンドは名前が小文字になっている ("kmsdrm", "rpi", "android", "psp", "ps2", "vita"). SDLは既にSDL_HINT_VIDEO_DRIVERはでは大文字小文字を無視する. しかし, アプリケーションでSDL_GetVideoDriver()またはSDL_GetCurrentVideoDriver()を呼び, 大文字小文字を無視せず比較している場合は, プログラムを変更する必要がある.

    SDL_VideoInit()SDL_VideoQuit()は削除された. 代わりにSDL_InitSubSystem()SDL_QuitSubSystem()をSDL_INIT_VIDEOで呼ぶこと. これで参照カウンタを正常にカウントできる. SDL_HINT_VIDEO_DRIVERで特定のビデオドライバを選択できる.

    ディスプレイのインデックス番号を反復処理するのではなく, 新しい関数SDL_GetDisplays()でディスプレイの一覧を得ることもできる. ディスプレイのインデックス番号を渡していたディスプレイ関数はSDL_DisplayIDを取るようになった. 不正なディスプレイIDは0である.

        {
            if (SDL_InitSubSystem(SDL_INIT_VIDEO)) {
                int i, num_displays = 0;
                SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
                if (displays) {
                    for (i = 0; i < num_displays; ++i) {
                        SDL_DisplayID instance_id = displays[i];
                        const char *name = SDL_GetDisplayName(instance_id);
    
                        SDL_Log("ディスプレイ %" SDL_PRIu32 ": %s", instance_id, name ? name : "不明");
                    }
                    SDL_free(displays);
                }
                SDL_QuitSubSystem(SDL_INIT_VIDEO);
            }
        }
    

    SDL_CreateWindow()は単純化され, ウィンドウの座標を取らないようになった. 生成時にウィンドウのプロパティを設定する必要がある場合は, SDL_CreateWindowWithProperties()を使うこと. 例:

        SDL_PropertiesID props = SDL_CreateProperties();
        SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title);
        SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x);
        SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y);
        SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width);
        SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height);
        // ウィンドウフラグはウィンドウ生成のプロパティとは分けるべきだが
        // SDL2から簡単に移行するために次のようにすることもできる:
        SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags);
        pWindow = SDL_CreateWindowWithProperties(props);
        SDL_DestroyProperties(props);
        if (window) {
            ...
        }
    

    SDL_WINDOWPOS_UNDEFINED_DISPLAY()マクロとSDL_WINDOWPOS_CENTERED_DISPLAY()マクロはディスプレイインデックス番号の代わりにディスプレイIDを取るようになった. この場合, ディスプレイID 0はプライマリティスプレイを表す特別な値である.

    SDL_WINDOW_SHOWNフラグは削除された. ウィンドウはデフォルトで表示され, 表示しないウィンドウはSDL_WINDOW_HIDDENフラグで生成できる.

    SDL_WINDOW_SKIP_TASKBARフラグはSDL_WINDOW_UTILITYフラグに置き換えられた. 機能は変わらない.

    SDL_DisplayModeにピクセル密度が追加された. この値はディスプレイモードのサイズよりもピクセルサイズが大きいとき1.0を超える値を取りうる. ウィンドウの背後のバッファの実際のピクセルサイズはSDL_GetWindowSizeInPixels()で得る必要がある.

    SDL_DisplayModeのリフレッシュレートはfloat型になり, 正確な値のため分母と分子も追加された.

    ディスプレイモードのインデックス番号を反復処理するのではなく, ディスプレイの可能なフルスクリーンモードの一覧を得る新しい関数SDL_GetFullscreenDisplayModes()が追加された.

        {
            SDL_DisplayID display = SDL_GetPrimaryDisplay();
            int num_modes = 0;
            SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &num_modes);
            if (modes) {
                for (i = 0; i < num_modes; ++i) {
                    SDL_DisplayMode *mode = modes[i];
                    SDL_Log("ディスプレイ %" SDL_PRIu32 " モード %d: %dx%d@%gx %gHz",
                            display, i, mode->w, mode->h, mode->pixel_density, mode->refresh_rate);
                }
                SDL_free(modes);
            }
        }
    

    SDL_GetDesktopDisplayMode()SDL_GetCurrentDisplayMode()はアプリケーションのメモリに書き込むのではなくディスプレイモードへのポインタを戻すようになった.

    ウィンドウを明確にフルスクリーンモードにする場合は, SDL_SetWindowFullscreenMode()を使用すること. ウィンドウのフルスクリーンモードはSDL_GetWindowFullscreenMode()で得られる. これはモードへのポインタを, またはデスクトップフルスクリーンのときNULLを戻す. SDL_SetWindowFullscreen()はbool値を取るだけで, フルスクリーン状態は選択したモードによる.

    SDL_WINDOW_FULLSCREEN_DESKTOPは削除され, ウィンドウがフルスクリーンのとき, 排他的フルスクリーンか仮想フルスクリーンかはSDL_GetWindowFullscreenMode()で得られるようになった.

    SDL_SetWindowBrightness(), SDL_GetWindowBrightness(), SDL_SetWindowGammaRamp(), SDL_GetWindowGammaRamp()はAPIから削除された. 現在のOSでは扱いが難しく, 効果をSDLウィンドウに限定することができないためである.

    シェーダーにアクセスするプログラムは, ポストエフェクトとしてレンダリングされたカスタムシェーダーコードを使用してより堅牢なバージョンの関数を実装できる.

    OpenGL設定からSDL_GL_CONTEXT_EGLが削除された. 代わりにSDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);を使用すること.

    SDL_GL_GetProcAddress(), SDL_EGL_GetProcAddress()はvoid *の代わりにSDL_FunctionPointerを戻すようになり, 正しい関数の型でキャストしなければならなくなった. SDL_FUNCTION_POINTER_IS_VOID_POINTERを定義すると以前と同じ動作になる.

    SDL_GL_DeleteContext()の名前はSDL(とglX/EGL)の命名規則に合わせるためSDL_GL_DestroyContextに変更された.

    SDL_GL_GetSwapInterval()は間隔を出力先引数として取り, 関数が成功したとき真, エラーのとき偽を戻すようになった.

    SDL_GL_GetDrawableSize()は削除された. 代わりにSDL_GetWindowSizeInPixels()が使用できる.

    ウィンドウフラグSDL_WINDOW_TOOLTIPSDL_WINDOW_POPUP_MENUはWindows, Mac (Cocoa), X11, Waylandに対応するようになった. これらのフラグを持つウィンドウは, SDL_CreatePopupWindow()関数で生成する必要がある. この関数にはポップアップさせる親ウィンドウを渡す必要があり, ポップアップウィンドウの位置は親との相対位置である.

    API関数が参照するウィンドウフラグであるSDL_WindowFlagsはUint32だったが, 64ビットに拡張された.

    SDL_GetWindowOpacity()は不透明度を出力先引数を使用せず直接戻すようになった.

    以下の関数の名前は次の様に変更された:

    以下の関数は削除された:

    IDの型SDL_Windowの名前はSDL_WindowIDに変更された.

    以下の環境変数は削除された:

    以下のシンボルの名前は次の様に変更された:

    以下のシンボルは削除された:

    次のウィンドウ操作は非同期リクエストとして扱われるようになり, 対応するイベントを受信するまで成功したとみなされなくなった:

    これらの関数の呼び出しの後, 即時に操作を適用したい場合は, SDL_SyncWindow()関数で待機中の全てのウィンドウ操作が完了するまで待つこと. SDL_HINT_VIDEO_SYNC_WINDOW_OPERATIONSヒントで, SDL2の動作に似せて全ての非同期ウィンドウ操作関数の呼び出しを自動的に同期処理にすることもできる. ウィンドウのアニメーションが完了するまで待つため, 同期させると長時間ブロックされる可能性があるので注意すること. さらに, ウィンドウシステムは要求を拒否したり, 正確に従わないこともある(例えばウィンドウはデスクトップの利用可能な領域やスクリーンの外に移動できない)ため, 対応するイベントが送られないことや, 期待する値が含まれない場合がある.

    SDL_vulkan.h (Vulkan)

    SDL_Vulkan_GetInstanceExtensions()はウィンドウを引数に取らなくなり, 結果のためにアプリケーションの領域を確保せず内部の静的な読み取り専用の文字列を戻すようになった.

    SDL_Vulkan_GetVkGetInstanceProcAddr()の戻り値はvoid *からSDL_FunctionPointerとなり, 関数はPFN_vkGetInstanceProcAddrへのキャストが必要になった.

    SDL_Vulkan_CreateSurface()は第3引数にVkAllocationCallbacksポインタを取るようになった. 渡すべきアロケータがない場合は, NULLを渡してシステムのデフォルトのアロケータを使うこともできる(SDL2はここでは常にシステムのデフォルトのアロケータを使用していた).

    SDL_Vulkan_GetDrawableSize()は削除された. SDL_GetWindowSizeInPixels()に置き換えることができる.

    SDL_vulkanInstanceとSDL_vulkanSurfaceは削除された. これらはTizenとの互換性のためSDL2に独自に組み込んだものだったが, アプリケーションをSDL3 APIに合わせてアップグレードする場合は変更が必要になる.

    SDL Wikiへのリンク

    Migrating to SDL 3.0