Showing posts with label WGL. Show all posts
Showing posts with label WGL. Show all posts

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

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.

Thursday, January 29, 2015

std::regexを使い、自力でOpenGL(WGL)バインド

WindowsでOpenGLを使う為にはwglGetProcAddress関数でAPIの関数ポインタを収集しなければなりません。文字列処理に長けたスクリプト言語でパーサを作って https://www.opengl.org/registry/ のヘッダからCのソースを生成するのが一般的かと思いますが、Visual Studio 2013でregexがstd::regexに移動していたのでC++だけでやってみることにします。
追加ライブラリ無しで正規表現が書けました。

STLに慣れているとstd::sregex_iteratorが奇妙に見えますが、これで複数のOpenGL関数定義を巡回させます。std::regex_matchでも正規表現を実行できますが、こちらは最初の一回しかマッチさせられません。マッチ結果はstd::smatchを使って戻り値、関数名、引数リストを取り出します。

GitHubはここです。