Saturday, February 28, 2015

Visual StudioとAndroid StudioでOpenGLを使ったマルチプラットフォーム開発

実際に構築してみました。ここにコミットしています。
ソースを共用しながら、AndroidとWindowsの両方で動かせるようにしてみました。C++を主に使うのでNDKも入れておきます。

Android StudioでassetsフォルダやC++のソースを階層の浅い場所に移動


Androidのassetsフォルダにテクスチャやシェーダーを配置します。ただ、eclipse時代と違ってAndroid Studioはデフォルトで app/src/main/assetsとすごく深い場所にあります。これでは不便なので、build.gradle に以下のように書いて使いやすい場所を指定します。(同時にC++のソースも浅い場所に移動しています)


main.assets.srcDirsはassetsを置く場所、main.jni.srcDirsはC++のファイルを置く場所です。'../../assets'のようにAndroid Studioのプロジェクトファイルより上位のフォルダも指定できることがわかりました。

Visual Studioからも同じソースやファイルを使うので、この任意のフォルダ位置を指定する機能は重宝します。


assetsフォルダをC++から使う


AndroidのassetsはC++から直接アクセスできないので、Javaを経由します。以下のようなヘルパークラスを作っておき、C++から使います。

Javaでは指定のファイル名でassetsフォルダから読みだしてバイト列にしてC++側に返します。C++側でJavaからバイト列をもらい、改めてcallocでメモリを割り当て直してコピーしています。callocでサイズを+1しているのは、テキストファイルの終端に'\0'を入れたいためです。


テクスチャをJava経由でC++から生成


Android機はGPUによって対応している圧縮テクスチャフォーマットが違うので面倒です。この対応は後で考える事とし、とりあえず手始めにjpgやpngなどをまず使えるようにしておきます。
AndroidではJavaから直接テクスチャを生成すると簡単です。assetsフォルダからBitmapFactory.decodeStreamでBitmapを生成し、更にBitmapからGLUtils.texImage2Dでテクスチャを生成します。JavaからC++に渡すのはGLuint型(Javaではint型)の生成済みのテクスチャを表すtexture nameだけなのでシンプルに実装できます。


Windows版の対応


それぞれAndroid版と同名のローダを作ります。

LoadFileはassetsフォルダのファイルをfopenでファイルを読み込むだけです。
LoadTextureViaOSではGDI+を使うことで、アルファチャンネル付きの32bitのrawデータが得られます。ここからテクスチャを生成しています。

GDI+とOpenGLではRGBAの並びが違うのでビットシフトで置き換えています。
OpenGLは以前作ったWGLGrabberを使って関数ポインタを取得しています。


ネイティブクラスの設計


基本的に出来る限りC++で処理すると決めたので、onTouchEventを使ったタッチ等のイベントは全部JavaからC++に渡します。また、GLSurfaceViewを使うので、onDrawFrameからC++のレンダラーを呼び出すことになります。

注意すべきはJavaのスレッドが2つあることです。onTouchEventはUIスレッド、onDrawFrameはレンダースレッドです。

今回は簡単にするため、タッチの座標だけ保存しておいてonDrawFrameの中からタッチイベントもC++に渡します。こうすることでC++は常にレンダースレッドで実行されることが保証されます。

将来的にはマルチスレッドの同期取りはC++側に移動したほうが最適化しやすいかもしれません。


まとめ


OpenGLを使った開発はOpenGL関連のコードが大多数を占めるので、このようにプラットフォーム依存する場所を開発の始めに括っておくと以後のマルチプラットフォーム化が楽になります。

Wednesday, February 18, 2015

DIY: Binding Lua5.3 with C++11

Let's bind C++ stuff to Lua5.3! :)

THE MEAT AND POTATOES


It might be enough to simple scripting for several projects.


BRUTEFORCE WAY


Our main weapon is C++, so the above code doesn't satisfies me. So, let's bind C++ classes and create instances from Lua.

It works fantastic. Then MyClass is able to be generated with scripting, and the garbage collector calls our destructor and delete it.
However, it might be unpleasant chore to make additional method and classes. The bind code is too long and messy!

HACKING


Let's make stuff fun. The most brilliant thing for us is we are living in future. Now, C++11 allow us what we couldn't do before.

Below code is all to bind MyClass:


Most simple binds are able to be written with lambda. So, for compile it C++11 must be enabled. To prevent crashes by scripting bug, define a GET_MYCLASS macro to ensure the first element of the Lua stack is our MyClass. Note that MyClass instances are constructed with placement new. In this case, the destructor must be called directly instead of calling delete operator.

BindClass defined like below:


As you can see, there is no MyClass dependencies. To avoid dependencies, I made a closer generator and put the class names and userdata creators into upvalue. Of course, BindClass can also be used for binding two or more extra classes.

CONCLUSION


Binding to Lua is not so complex and easy to learn. It's only combinations of small number of features such as stack and metatables. I saw programmers bothered increasing binding codes. I bet we can simplify them. Hope this helps to find your own solution.

自力Luaバインド 決定版

前回の続きです。クロージャでクラスのインスタンス生成をすっきり書けそうなのでやってみました。 ここまでシンプルにかければ、バインドの為の外部ライブラリの力を借りずとも十分やっていけそうです。BindClassという新たな関数が追加され、こちらに雑多なコードが移動しています。BindClassがuserdataを生成するだけの関数(ラムダで定義)を引数としている点がポイントです。ラムダでは前回同様userdata上にplacement newでインスタンスを初期化します。 BindClassもこれだけで、特定のクラス名などが取り除かれ汎用化されています。CreateClassMetatableでメタテーブルを生成するのは定番のコードです。

C++にだけ慣れていると奇妙に見えるのはCreateCppClassInstanceです。これはLuaから呼べる関数型をしていますが単独では呼べません。upvalueという領域にクラス名とクラスのインスタンス生成を行う関数を結び付けてクロージャを生成しておくことで初めて関数として呼べるようになっています。そのクロージャを生成してクラス名と同名のグローバル関数を登録する部分がCreateClassInstanceCreatorです。

このようにしてクラスの種類数だけクロージャを生成することで、どんな種類のクラスインスタンスもCreateCppClassInstanceに生成させることが出来るようになります。

ところで、CreateCppClassInstanceのactualInstanceCreatorはlua_CFunction型として取り出して、直接CからactualInstanceCreatorを呼び出しています。これはBindClassの引数として受け取っているcreatorです。ということは、Luaが直接creatorを呼び出すことは無いのでlua_CFunction型を使う必要は無いということです。lightuserdataとして任意の型の関数にしても問題なさそうです。

LuaのC++バインドをラムダ式で書く

以前LuaからC++のクラスを使えるように自前バインドを書きました。しかし、非常に冗長でした。規模の大きいクラスになると恐ろしい長さになりそうです。そこで、C++11の恩恵に与りながら短く書き直してみました。

まず、luaL_setfuncsで複数関数を一気に登録します。その際luaL_Regの配列を渡すのですが、関数部をラムダ式で書きます。MyClassのポインタはGET_MYCLASSというマクロで取得し、更に万一型が合わないなどで取得に失敗してもクラッシュしないようになっています。

また、placement newでMyClassのメモリ確保をluaに任せるようにします。これによってダブルポインタを使う無駄を省いた上にコードもすっきりしました。deleteのかわりにp->~MyClassを明示的に呼ぶ必要があります。placement newを使うためには #include <new>が必要です。

単独のサンプルとしてはこのくらいが最短かと思いますが、複数のクラスをバインドするなら上のコードの一部を共通化できるのでもう少し短くなりそうです。例えばメタテーブルを生成して__indexに自身を指定するあたりはサブルーチン化します。

MyClassNewはマクロ化すれば複数クラスで使いまわせそうです。本当はテンプレート関数化したいところですが、メタテーブルに渡す文字列をテンプレート引数にするにはややトリックが必要です。現状のC++では文字列定数をテンプレート引数に出来ないためです。


Tuesday, February 10, 2015

Luaでシェーダ言語のベクトルのswizzlingのようなことをしてみる

3DをやっているとLuaからC++のベクトルや行列にアクセスしたいことがあります。今回の目標はLuaからC++のベクトルを作って、更にシェーダ言語のswizzlingみたいなことをしてみます。例えばこんな感じに書けるようになります。 これをやるためにはメタテーブルの"__index"と"__newindex"をそれぞれC関数として、実行時に解釈します。以下全ソースです。 swizzlingして読みだす時(右辺に来るとき)はVec4Index、swizzlingして書き込む時(左辺にくるとき)はVec4NewIndexが呼ばれます。

Vec4NewIndexで、代入する値がベクトルであってもスカラーであってもいいようにLUA_TNUMBERとLUA_TUSERDATAに分岐しています。

Luaからベクトルの長さを得るGetLengthというメソッドがあります。BindVec4関数内でバインドしようとしているのはだめな例です。なぜならBindVec4で作っているのはメタテーブルであって、__で始まるメタメソッドは定義出来ても任意のメソッドは定義できません。前回のMyClassはメタテーブルの__indexにメタテーブル自身を参照させていたのでメタテーブル内に任意のメソッドを定義することができましたが、今回は__indexをswizzlingのためのC関数であるVec4Indexにつかってしまっています。

ではどうするのかというと、Vec4Index関数の中で"GetLength"を参照しようとしたかを判定してVec4GetLength関数を返しています。これでLuaからGetLengthが使えます。

テストはこれでいいかもしれませんが、実際に使えるものにするにはもうひと工夫する必要がありそうです。


Monday, February 9, 2015

Lua stack dump (WRONG CASE)

This is very simple Lua stack dumper. It extracts all element values by using lua_tostring whatever the types is not a string. It looks work well, but the problem is that lua_tostring overwrites values in the stack by string version.

One of correct code is below. The programmer always needed to take a step to ensure their correct types when accessing the Lua stack.

Sunday, February 8, 2015

DIY: Bind OpenGL(WGL) APIs using std::regex

Windows SDK doesn't provides direct way to access modern OpenGL APIs. So, as you know developers suffer to choose the method to acquire huge amount of address of WGL APIs. (or just decide using GLEW)

The popular DIY option is parsing the Khronos Group's extension header files with script languages and generate C++ glue code. But, I didn't. A good news is std::regex is now available on Visual Studio 2013, So I felt it's the simplest option to do.

Tools are always getting better and better! Isn't it?:)

std::sregex_iterator looks wired from the perspective of STL programmers, but it is the way for multiple match of OpenGL API declaration in the header files.(std::regex_match is only for single match, it wasn't for me) and std::smatch contains divided parts of a declaration, such as name of API, return type and parameters.

My project files are available on GitHub.

Saturday, February 7, 2015

Lua5.3を自力バインド

LuaとC++を自力でつないでみます。

以前はtolua++を使っていましたが、グルーコードを毎回生成するのが意外と不便でした。ヘッダの日付が変わってしまったために全体ビルドがかかってしまったりします。nmakeやバッチファイルを導入してみたり、自動生成したファイルをバージョン管理に含めるべきか悩んだりしました。結局外部定義ファイルよりはcppに直接バインド内容を書けてしまうほうが悩まないかもしれません。

例えば、WindowsのMessageBoxをLuaから使えるようにするコードです。あっけないほど簡単です。わざわざ外部のライブラリを導入する必要もないです。プロジェクトの性質によってはこれで十分用足りるでしょう。

ここからが本題です。C++を使うからにはC++っぽいことをしたいわけです。目指す仕様は、
・C++のクラスをバインドしてLuaからインスタンスを作る
・グルーコードでnewからdeleteまで勝手にやってくれる
・ガーベージコレクションの時点でdeleteさせたい

これを実現したコードが以下です。

C++のBindMyClass関数でLua内にMyClassというクラスをメタテーブルで定義します。MyClassはSetValueとGetValueという2つのメソッドを持ち、__gcでガーベージコレクションの直前に呼ぶ関数があることをLuaに教えます。__indexはやや特殊ですが、MyClassのインスタンスがメソッドを探しに行くテーブルがメタテーブル自身であることを示します。これによってメタテーブル内にメソッドを定義できます。

最後のlua_registerで"MyClass"という名前のLua関数を呼ぶとC++側のMyClassNew関数がインスタンスを生成して返します。クラス名と同じ名前の関数として登録していますが関数名は何でも構いません。MyClassNewではLuaのユーザーデータを生成してC++側で生成したMyClassのポインタを格納し、先ほど作っておいたMyClassのメタテーブルを設定します。

MyClassSetValueとMyClassGetValueはLua側からC++側の変数に値を格納したり取り出したりする所です。せっかくなのでLua5.3の新機能である整数形式を試してみます。lua_Integerはデフォルトで64bitになりました。よって、int型に代入する場合キャストしないとwarningが出ます。

一見複雑ですが、アセンブリを読むような難解さはあれど覚えることはそう多くはないです。一度自力でバインドする方法を試しておくと、たとえ他のオープンソースのバインダーを使う場合でもより理解しやすくなるはずです。

GitHubはここです。