前回記事ではVita用にminiJVMというJVMをビルドして動作させてみるという内容で記事を書きました。
今回はそのJVMを利用して、画面を出すということをしてみたいと思います。
はじめに
前回記事ではVitaでminiJVMが動いたよ~~~という記事を書きました。
とはいってもまだまだHello Worldが出せただけで、Javaでprintfが叩けただけという話になります。
やっぱりVitaでプログラムを動かすうえでは、コントローラーを使ってGUIをグイグイ動かしていきたいと思うわけなので、グラフィックをやっちゃおうかなと思います。
まずはCで…
というわけで、Vitaで本当にグラフィック書けるのかいな??ってところですが・・・まずはC言語で書いてみて動くことを確認しました。
VitaSDKではすでにSDLをVita向けにビルドしたものが提供されていて(すごい!)、以下のサンプルコードを動かせば赤い矩形が表示されるプログラムを組むことができます。
samples/sdl2/redrectangle at master · vitasdk/samples · GitHub
自分はここにイベントを処理するコードを追加して、矩形が上下左右にコントローラーでぐりぐり動かせることも確認しました。もうこれで簡単なゲームなら作れますね(笑
SDLについてご存じない方向けに説明すると、マルチメディアを取り扱うにあたって各クロスプラットフォームにおける差異を吸収(抽象化)して取り扱えるようにしてくれるライブラリになります。ぼくも10年ぐらい前に触ったな・・・また出会うことになるとは(遠い目)
Javaでグラフィックを表示できるようにする
というわけで、C言語での練習を経て、Javaでのグラフィック表示を実装していきたいと思います。コチラについてはJavaでSDL叩けるようにJNIでライブラリを書けばいいのかなと思っていますが、果たして。なお、2023年2月現在、Java Bindingsについては提供されていない模様。
Simple DirectMedia Layer - Language Bindings
まずはWindowsでビルドできるようにする
ターゲットはVita環境ですが、現在のままだとデバッグもしづらいので開発環境で動かせるようにすることでデバッグしやすくしたいと考えました。
Support for building on MSVC by ohayoyogi · Pull Request #19 · digitalgust/miniJVM · GitHub
というわけで、Visual Studioで開発できるように修正してみました。これ今見るとプルリク取り込んでもらえたみたいなので、Visual Studio使って開発することができるようになりました。(cmakeでVisual Studioのソリューションファイルを生成したりするのは他をググってください)
WindowsでSDLを叩くライブラリを書く(JNI)
DLLのロードの仕方が違うなどの問題はあるので、そのままは適用できないと思いますが、最低限度デバッグはできると考え、SDLを使ってみるところまでコードを書いてみたいと思います。
まずは普通にJavaからJNIでSDLを使ってみるコード。コード書いてて気づいたんですが、どうもSDLを起動したスレッドじゃないとイベントハンドリングしちゃだめっぽいので、「スレッド1)初期化・開始・イベントループ・終了」「スレッド2)描画ループ」みたいな感じで関数分けようかなと。ライブラリの中でスレッド立ち上げるのは正直怖いので、Java側でスレッド分けて、C言語(JNI)でInit, Start, EventLoop, End, Paint みたいな関数を用意することにしました。
ちなみに、JNIとはJava Native Interfaceの略で、他の言語で書かれたネイティブなライブラリをJavaから呼べるようにする規格です。昔の自分が聞いてもちんぷんかんぷんでしょうけど、今なら書ける、書けるぞ!!!
インタフェースの仕様はわかりやすく、簡単なお作法を覚えれば動くところまではいくかなという感想です。ただ、まぁ注意して書かないと特定環境でしか動かない代物ができてしまいそうでチョット怖い。
miniJVM用のJNIに書き換えてみる
ノーマルのJVMで動くことが確認出来たらそれをminiJVMに移行していきます。
ここで注意が必要なのは、miniJVMはオレオレJNI仕様 となっていることです。ライブラリをロードしたときに JNI_OnLoad 関数が呼ばれる、ここまではいいんですが、読み込ませたい関数を native_reg_lib
関数で jvm に登録してあげる必要があります。
ここら辺の仕様についてはminiJVMのOpenGLのラッパ関数実装(以下リンク)を見てあげるのがよいかなと思います。引数に配列を取る場合やlongを返す場合など参考になるコードを読むことができます。
miniJVM/jni_gl.c at master · digitalgust/miniJVM · GitHub
というわけで動作するようになったものがこんな感じ↓
終わりに
と、ここまでで相当長くなってしまった(というかここから先に進むのに時間がかかりそうな)ので、今回はここまでとしたいと思います。
今回思ったのはJNIのロードまわりを改善していくといいのかなと。ここら辺がOpenJDKの仕様と合わせられるとプリプロセッサで分けるなどの必要がなくなりますし、、、、ちなみに今回はこんな感じで書いてます(地獄
#ifndef _FOR_MINIJVM JNIEXPORT void JNICALL Java_org_hoge_piyo_SDLAdapter_End (JNIEnv *jenv, jclass cls) { #else JNIEXPORT int JNICALL Java_org_hoge_piyo_SDLAdapter_End (Runtime *runtime, JClass *cls) { JniEnv *jenv = runtime->jnienv; #endif printf("SDL_End"); #ifndef _FOR_MINIJVM } #else return RUNTIME_STATUS_NORMAL; } #endif
ここら辺がスッキリすると非常に良いのではないかなと!まー寄り道してると自分のやりたいことの実現が遠のくので、達成してから還元は考えたいと思います。