SDL2を利用したAndroidサンプルアプリを試してみる

SDL2ではAndroid向けのビルドもサポートされています。SDL2を用いたサンプルプログラムを動作させてみます。また簡単なテトリスをLinux上とAndroid上で動作させてみました。

 

1. SDL2のインストール

ダウンロードのページにOSX向けのdmgファイルがあります。

Ubuntu 12.04ではSDL1.2のパッケージはありますが、SDL2のパッケージはない ようです。下記手順でビルドできます。

$ sudo apt-get build-dep libsdl1.2debian
$ wget http://www.libsdl.org/release/SDL2-2.0.2.tar.gz
$ tar zxvf SDL2-2.0.2.tar.gz
$ cd SDL2-2.0.2
$ ./configure # --prefixを指定しない場合は/usr/localにインストール
$ make
$ sudo make install

2. Android向けのサンプルプログラム

チュートリアルのページにサンプルが紹介されています。 

Androidのサンプルのページではmain.cとimage.bmpというファイルを利用した サンプルが紹介されています。main.cはウィンドウを作成し、image.bmpを表 示するプログラムです。

3. OSX向けのビルド

ウィンドウのサイズを400x400に変更します。

$ diff -uprN main.c.org main.c
--- main.c.org  2014-03-14 10:28:07.000000000 +0900
+++ main.c      2014-03-14 10:27:50.000000000 +0900
@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
     SDL_Window *window;
     SDL_Renderer *renderer;
 
-    if(SDL_CreateWindowAndRenderer(0, 0, 0, &window, &renderer) < 0)
+    if(SDL_CreateWindowAndRenderer(400, 400, 0, &window, &renderer) < 0)
         exit(2);
 
        Sprite sprite = LoadSprite("image.bmp", renderer);

コンパイルします(インクルードファイルのサーチパスは-Iで指定する以外の 方法はないのですかね?)。

clang -framework SDL2 main.c \
-I/Library/Frameworks/SDL2.framework/Headers/

実行するとウィンドウが開かれます。クリック等のイベントで終了します。

OSXでの実行結果
OSXでの実行結果

4. Android向けのビルド

こちらは先ほどとは異なり、ウィンドウサイズを指定する必要はありません。 SDL2のディレクトリに格納されているAndroid向けのビルド用ディレクトリを コピーして利用します。

$ cp -a SDL2-2.0.2/android-project .
$ cd android-project

main.cをjni/srcディレクトリ配下に格納します。

$ cp ../main.c jni/src/

image.bmpをassetsディレクトリ配下に格納します。 SDL_loadBMPを実行すると assetsディレクトリ配下のファイルが読み込まれます。

$ mkdir assets
$ cp ../image.bmp assets

main.cをビルド対象とする為にjni/src/Android.mkを編集します。

--- jni/src/Android.mk.org      2014-03-14 10:59:53.000000000 +0900
+++ jni/src/Android.mk  2014-03-14 11:03:00.000000000 +0900
@@ -10,7 +10,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_
 
 # Add your application source files here...
 LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \
-       YourSourceHere.c
+       main.c
 
 LOCAL_SHARED_LIBRARIES := SDL2
 

SDLのコードを参照させる為、jniディレクトリ直下にSDLディレクトリのシン ボリックリンクを作成します。

$ cd jni
$ ln -s ../../SDL2-2.0.2 SDL #SDLでないとビルドエラー
$ cd ..

antでjniディレクトリ配下をビルドする為、custom_rules.xmlを追加します。

$ cat custom_rules.xml 
<?xml version="1.0" encoding="UTF-8"?>
<project>
  <target name="-pre-build">
    <exec executable="ndk-build" failonerror="true"/>
  </target>
</project>

android update projectを実行し、antでビルドできるようにします。 -t 4は環境依存の値なので、各々のandroid list devicesで確認できるターゲッ トを指定して下さい。

$ android update project -p . -t 4
Updated project.properties
Updated local.properties
Updated file ./proguard-project.txt

android-mode.elでビルドすると以下の出力を得られます。SDL2を静的リンク する為、SDL2のビルドが実行されています。

-pre-build:
Android NDK: WARNING: APP_PLATFORM android-16 is larger than android:minSdkVersion 10 in ./AndroidManifest.xml    
[armeabi] Compile thumb  : SDL2 <= SDL.c
[armeabi] Compile thumb  : SDL2 <= SDL_assert.c
[armeabi] Compile thumb  : SDL2 <= SDL_error.c
[armeabi] Compile thumb  : SDL2 <= SDL_hints.c
[armeabi] Compile thumb  : SDL2 <= SDL_log.c
[armeabi] Compile thumb  : SDL2 <= SDL_audio.c
<snip>
[armeabi] SharedLibrary  : libSDL2.so
[armeabi] Install        : libSDL2.so => libs/armeabi/libSDL2.so
[armeabi] Compile thumb  : main <= SDL_android_main.c
[armeabi] Compile thumb  : main <= main.c
[armeabi] SharedLibrary  : libmain.so
[armeabi] Install        : libmain.so => libs/armeabi/libmain.so
<snip>

emulator上で実行すると以下の画面が表示されます。画面タッチ等のイベント で終了します。

Android上での実行結果
Android上での実行結果

5. まとめ

SDL2を利用することで、他環境で作成したSDL2のプログラムをそのまま流用で きます(SDLActivity.javaからJNI経由でmain関数が呼ばれる為)。 onResume/onPauseの際にデータ退避等はどうするかが気になるところ(仕組み は用意されているみたいです)。

6. 使ってみて気になった点

しばらく使ってみて気になった点を挙げてみます。

 

6.1. 環境依存

Androidの場合、main関数で作成したスレッドでSDL_EventPollやSDL_EventWaitによるイベントハンドリングが可能であるのに、OSX等では可能ではありませんでした。前処理に違いがでてくるのでしょうかね。#ifdef ANDROIDで切り分けする必要がありました。環境依存の原因が判明するまで色々試行錯誤が必要なので、スムーズに移植が可能とはいかないかもしれません。

 

6.2. 文字列の表示

 SDL単体では文字列を画面に描画する機能がありません。そこでSDL_ttfを用いて、以下の処理を実装することになります。

  1. TTFファイルの読み込み
  2. 文字列の生成(例えば、文字列をファイルから読み込む処理)
  3. 文字列用のテクスチャの作成
  4. テクスチャの表示

描画の処理毎に3と4を実行するので、気になります。予めTTFファイル読み込み時に全ての文字データをテクスチャにしておきたいのですが、どんな文字列が来てもいいようにするのは難しいです(アルファベットなら可能ですけど、漢字まで含めるとできないような)。せいぜい、同じ文字列の表示はキャッシュしたテクスチャを使うとかが関の山ですかね。通常のGUIライブラリはどうやってるのでしょうか。SDL_DrawStringみたいなAPIが欲しいところです。でないと文字列の表示を実装するコストが必要になります。

 

6.3. BlueTooth

例えばゲームでBlueToothによる通信をしたいと思っても、SDLが対応していないし、そもそもndkのライブラリにもAPIがありません。

7. SDL2のテトリスをLinux上とAndroid上で動作させる

githubにSDL2で実装したテトリスを公開しました(かなりやっつけではありますが)。Ncursesでも動作します。