NDKのndk_helperモジュールを使う

この記事は、[Android Advent Calendar 2013](http://qiita.com/advent-calendar/2013/android)の12/8の記事です。

##はじめに
こんにちは、hak (@hak)と申します。GoogleのAndroidチームでDeveloper Advocateをしており、主にOpenGL、OpenSL、NDK等ゲーム技術担当をしています。
本記事では先日アップデートされたAndroid NDK r9bの新機能、特にNDK用のヘルパモジュール、"ndk_helper"の紹介をします。

##Android NDK r9b
NDK r9bは先日リリースされたNDKの最新版で、下記のような新機能がサポートされています。
・hard-float ABIサポート
　浮動小数点引数、戻り値を持つ関数呼び出しのレジスタ使用を最適化することができます
・RenderScriptバインディング
　C/C++コードからRenderScript APIを直接呼び出しできます
・ndk_helperモジュール追加
　ゲーム用途等のヘルパモジュール
・サンプル追加
　OpenGL等の基本サンプル

　この記事では、ndk_helperモジュール、サンプル追加の２点について解説します。

##ndk_helperモジュールとは
ndk_helperモジュールはNDK r9bから追加されたNDKネイティブ・アプリケーション用のモジュールで、ゲーム等のアプリケーション実装に必要となるヘルパ関数を集めたものです。
これらのヘルパ関数を使うことによって、よく使われる実装の手間が省ける点、またドライバのバグ回避等のバッドノウハウや挙動の違いの吸収も目的としています。
**開発、メンテナンスは自分が行っていますので、機能追加要望、バグ報告等あれば、是非お願いします。**

##ソースコード
ndk_helperのソースコードは$ndk/sources/android/ndk_helperに収録されています。
最新版のndk_helperはr9bに収録されているものから関数名、namespace等が大幅に変更されています。これからndk_helperを見てみる、という方は下記のAOSPリポジトリから最新版ndk_helperのソースコードを取得するのがお勧めです。https://android.googlesource.com/platform/development/+/master/ndk/sources/android/ndk_helper/

##機能概要
NDK r9b収録バージョンでは、ndk_helperは下記のコンポーネントから構成されています。
現状、コンポーネント毎にcppファイル+ヘッダの構成です。

*gestureDetector*
シングルタップ、ダブルタップ、ピンチ処理等を行うジェスチャデテクターの実装です。タッチのタイミング、遊び等のパラメータはJavaSDKと同一の挙動を実装してあります

*shader*
シェーダコンパイル用のヘルパファンクションです。コンパイル時にソースコード内のパラメータ置換等が可能です。

*GlContext*
EGLコンテクスト、GLSurfaceの管理を行うヘルパです。
AndroidのActivityライフサイクル上、EGLコンテクスト、GLSurfaceは様々な理由で無効になりますが、出来るだけコンテクストを無効化せずに、vbo、texture等のGPUリソースを保持できるように実装してあります。Java APIのsetPreserveEGLContextOnPause()と同等の挙動です。

*tapCamera*
タッチ操作によるトラックボールカメラコントロール用のヘルパです。

*JNIHelper*
Java SDK APIをJNIコールで呼び出すためのヘルパファンクションです。
現状、テクスチャロード、ファイル読み出し、文字コード変換等のヘルパが実装されています。
なお、JNIHelperの使用にあたってはJava側に対応するコードNDKHelper.javaが必要です。

*interpolator*
いわゆるtween処理用の補間ライブラリです。Ease In, Out等各種の補間タイプをサポートしています。

*vecmath*
OpenGL用のベクタ演算ライブラリです。neon等のSIMD実装は今後の課題で、現状はピュアなC++実装になっています。(neon最適化をしてみたい方は連絡くださいw)

*perfMonitor*
現時刻の取得等、パフォーマンス計測用のヘルパです。

##使用方法
ndk_helperを使用するにはandroid.mkに下記の記述を追加して下さい。

```
$(call import-module,android/ndk_helper)
```

また、ヘッダファイルのインクルードも必要です。

```cpp
#include "NDKHelper.h"
```

##使用例
ndk_helperの使用例として、サンプル中よりドラッグ処理部を抜粋してみます。
ndk_helperのヘルパ関数は全て名前空間ndk_helperに定義されており、C++クラスとして提供されています。

```cpp
            Engine* eng = (Engine*) app->userData;
            //ドラッグ・デテクタでジェスチャ認識
            ndk_helper::GESTURE_STATE dragState = eng->drag_detector_.Detect( event );

            if( dragState & ndk_helper::GESTURE_STATE_START )
            {
                //ドラッグ開始
                ndk_helper::Vec2 v;
                eng->drag_detector_.GetPointer( v );
                eng->TransformPosition( v );
                eng->tap_camera_.BeginDrag( v );
            }
            else if( dragState & ndk_helper::GESTURE_STATE_MOVE )
            {
                //ドラッグ処理
                ndk_helper::Vec2 v;
                eng->drag_detector_.GetPointer( v );
                eng->TransformPosition( v );
                eng->tap_camera_.Drag( v );
            }
            else if( dragState & ndk_helper::GESTURE_STATE_END )
            {
                //ドラッグ終了
                eng->tap_camera_.EndDrag();
            }
}
```
はい、スッキリ、シンプル、簡単ですね。

##サンプル
ndk_helperモジュールの具体的な使用例としてNDK r9bには２種類のサンプルが追加されています。

*Teapot*
いわゆるユタのティーポット（通称やかん）を表示するサンプルです。
シェーダ、IBO、VBO等のOpenGLES2.0基本処理をデモします。

*MoreTeapots*
OpenGL ES3.0の Geometry Instancing機能とUniform Buffer Objectを使用して、512個のやかんを表示します。Snapdragon S800、Tegra4、Mali T604等のモダンなGPUでは楽々60FPSで動作します。
Uniform Buffer Objectを使用すると、これまでのUniform数の制限から解放される大変お勧めの機能の一つです。ただし、一部機種のドライバではUBO使用時にコンパイルエラーが発生するため、その場合はOpenGLES2.0相当の機能にフォールバックするよう、調整を入れています。

##今後の予定
今後、さらにヘルパ関数の追加、拡張を予定しています。
現状下記のようなプランですが、ご意見等あれば聞かせてください。
・Low Latency Audio実装
・NDKからJava UIを使うためのヘルパ
・その他サンプル追加

ということでひとつ、ndk_helperよろしくおねがいします。:)