12時間以上寝てしまった。土曜は2時くらいには寝たつもりなんだが、起きたら15時だった。
風呂入ったら頭痛くなってなんかやばいかと思ったが、やる気はあったので作業して寝たら治った。よかったよかった。
RTMPの視聴ができるようになったと思ってたんだが、やっぱ無理って報告があって自分でもやってみたらだめだった。
ローカルでOBSからPeerCastStationに配信してそれをそのまま視聴する分には動いてるので、なんかちょっとしたところで間違ってるんだろう。 デバッグしてみるとデータが壊れてる時に出る例外が大量に記録されてた。これだなー。
データが壊れてるっぽい時は1バイト読み飛ばして次のデータが読み込めるか確認するんだが、その度に例外飛ばしてるからめちゃくちゃ遅いようだ。例外じゃなくてgotoでふっとばすか……。C#のgotoは結構使いやすくて好き。gotoで速くはなったんだけどまだ上手く再生できないなぁ。やっぱり度々パケットの破損が検出されてるのが気になる。基本的には壊れないはずなんだが?
その後も調べてると、単にデータが追加できた時に書き込んでいる位置が間違ってることに気付いた。 上流からデータ受け取ったときにFLVとして解析するためのバッファに書き込むんだが、ちゃんとバッファの末尾に追加しなきゃいけないのに、先頭から上書きしてるっつーね。そりゃ壊れるよ。そこを直したらちゃんと再生できるようになった。やったー!
ローカルで再生してて大丈夫だったのはパケット分割とか行われる前だからだろうか。単に速くて現象が発生しなかっただけかもしれん。
再生はできるようになったのであとしばらく使ってみて問題なさそうならリリースしたいかなぁ。
Rubyでゲームなんか作れねーと言ったな、あれは嘘だ。……と、言えればよかったんですが。
F#で書こうと頑張ってみたんだけど、なんかF#に違和感がある。オブジェクトのメンバを呼び出す場合にはほぼ確実に型を明示しないといけないあたりがどうもかっこわるい。いろいろ調べてみたけど、そういうものっぽいのでちょっとF#意欲が減退した。
ところでここにmirahというものがあってな。 というわけでmirahというキワモノ言語に手を出してみることとした。 Ruby(っぽい何か)のコードをJVM用に静的コンパイルできるやつだ。
サーバ側ならともかく今時デスクトップにJREなんてみんな入れてないでしょっていう思いもあるが、JVM用のバイナリならいろんな方法でなんとかしようもあるのでいいかなーと。最悪IKVM.NETで.NET上で動かせばよくね?っていう感じ。
mirahはRubyっぽいコードを静的コンパイルできるが、Javaの標準ライブラリのみで動くようになる手前、Rubyの便利な機能はあんまり使えない。 基本的な数値・文字列・配列なんかはJavaのそれ(配列は違うかもしれない)に直接マップされるし、ブロックも自由には使えない。 そのかわりJavaのクラスに直接マップされるおかげでmirahのランタイムみたいなのは必要ないし、それによるオーバーヘッドも無くて済むってわけだ。 あと引数等の型もある程度は推論してくれるものの、基本的には明示する必要がある。 これもちょっとめんどいが、Rubyのコードにあちこち手を入れるだけでコンパイルできちゃうのはやっぱり便利だ。 F#ではだめでmirahは良さそうってのはその辺り。 ただまあ全面的にこいつでゲームを作るのはめんどくさすぎるだろう1。 というわけで基本的にはJRubyで、一部mirahを使うことにする。
IronRubyではOpenGLバインディングにOpenTKを使っていたが、JRubyではlwjglを使う。最近では(以前からだっけ?)ウィンドウ生成とか入力の処理にGLFWを使うようになったみたいでまあわかりやすい。 とりあえずlwjglのサンプルをJRubyとmirahに移植してみて感覚を掴んだ。
mirahはこのRuby派生言語によくあるパターンではあるが、言語仕様がしっかりドキュメントになってなくてよくわからないところが多少あったが、JRuby用のコードとそう大きく変わらずに動かすことができた。便利だなー。コンパイルエラーメッセージが分かりづらいのはなんとかしてほしいところ。
サンプルだけではなんなので今までIronRubyで作ってたゲームをJRubyに移植しよう。OpenTK依存の部分はちゃんとファイル分けてあったので、それのlwjgl版を作るだけだ。 いろいろとlwjglの使い方とかJRubyの使い方とかJavaのByteBufferの使い方を調べつつ、なんとか(というには比較的あっさり)動くようになった。 フレームレート的にはIronRuby版の1.5倍くらいになったな。mirahとか使ってないからIronRuby版とほぼ同じ条件なのにね。 やっぱりJRubyはIronRubyに比べてだいぶ速いなぁ。
フレームレートが1.5倍とはいっても、Atomマシンだと15fps程度がせいぜいだし、メインPCでも60fpsは行かない程度。たぶんデバッグ用の文字表示が重いけども、今後いろいろ載せたら重くなることを考えると、その程度で重いと言ってるようではやっぱりだめだよね。ということでmirahの力を借りる必要はありそうだ。
というあたりが今の状況。 これからmirahにちょこちょこ書き換えていくかなーと思ったけど、その前に考えるところがありそうだな。
以前からなんとなく思ってたけど、メモリ管理をちゃんとしたい。lwjglでは特に。 lwjglではglUniformMatrix4とかにFloatBufferとかByteBufferを作って渡すんだけど、こいつらは配列をwrapしたものじゃだめでダイレクトバッファというアドレスを直接取れるバッファじゃないとだめらしい。 glUniformMatrix4とか呼ぶ度にバッファ割り当てて、そこにデータコピーして渡すでもいいし今はそうやってんだけど、毎度割り当てとコピーはもったいないので、Matrixなりは内部的にバッファを割り当てて直接渡せるようにしないとだめだよね。 あとはUniform Bufferとか使おうと考えた時には、長いバッファオブジェクトの一部をMatrixやVectorとしてアクセスできるようにした方がよかろう。というわけで、バッファとそのビュー的なオブジェクトを作って、その上にVectorとかMatrixとかアクセスできるようにしたい。 なかなか大掛かりな作りになっちゃうけど今後のことも考えると今やっといた方がいいよなー。
こうやってゲーム作りは進まないのである。
なぜかfloatリテラルが無いというゲームにはかなり厳しい問題もある。float(1.0)
のようにすれば回避できるんだけどめんどいし、たぶんこれキャストするコード生成されてんだろうなぁ ↩