ボタン入力テスト、とりあえずできた。
*
しかし、テストコードが妙に長くなってしまっている。
設計を改善して機能の独立性を上げれば、もっと短くできるはずだ。
テストコードがあればそういうところも見えて来るんだな。
やはり自動テストは開発に必須だ。
ようやっと画面のテストができるようになったかもしれない。
*
brownsugarへの機能追加によって挙動を模倣し、fgへの関数追加でテストしたいデータを参照できるようになった、はず。
fgに追加した関数はあからさまなテスト専用のデータ参照関数にはなってないはずなので、あまり不自然ではない、と思う。
とりあえず、画面初期化時のテストはできた。
ボタン入力後の反応テストについて、明日から試していく予定。
brownsugarとかいうのを作り始めた。
*
zarameを使ってテストを動かそうとしたがうまく行かず、色々めんどうになったのでテスト用のベースシステムライブラリを作ってしまうことにした。
それがbrownsugar。
いい名前が思い付かなかったので適当だ。
*
基本はsucrose-testとかいう、sucroseのテスト用に用意したライブラリ。
fg::BasesystemContextやfg::GameContextがないとテストできない機能のために、そのダミーを生成するために用意したライブラリだ。
テストのテストというのも奇妙だったからか、ダミーとしての機能のテストをしていなかったため、それをきちんと追加する。
処理内容は丸々コピーする形になると思うけど。
とはいえ、そのままではkasuteraのテストに必要な機能が足りないので、その辺は順次足していく感じで。
自動テストをできるようにしたい。
*
fgを実装したライブラリを利用する、ゲーム側がまともにテストできていない状態で非常に困っている。
きちんと作れているのか確証が得られないため、とても不安だ。
*
画面単位であれば、テストは可能な作りになっているはずなのだ。
問題は、ゲームコントローラの入力に依存している処理があるため、既存のベースシステムでは全自動のテストができない。
あらゆるイベントを自由に生成できる環境を作れば、全自動でテストできるようになるかな。
いや、今のところ任意に発生させるのが困難なのはコントローラ周りだけだし、その辺だけでいいのか?
テストができない原因もそこだしな。
*
いや待て、コントローラの接続とかは外部公開の関数にしてたな、と探してみたらあった。
これ使えばzarameをそのまま使ってもテストできるかな。
zarameはlinux上で動かすためにudev関係のライブラリとリンク、つまり環境依存してるから、その辺排除した別のものを作った方がいい気がするけど。
後々、別のOS上でテスト実行したい、ってなった時大変だ。
とりあえずzarameで試してみよう。
fg::StatePopperに修正を入れるべきかも。
*
1回だけポップができるもの、として用意したのだが、破棄時にポップされるという仕様がよくないようだ。
破棄しようとすると絶対にポップされるため、ポップせずに破棄、ということができないのだ。
よって、ポップしなくてもいい場合にもポップが行なわれてしまう。
今の実装ではfg::StatePopperはfg::StateStackの参照をキャストしただけのものであってメモリを確保していないため、破棄せずにリリースすれば問題ない。
しかし、運用を考えると逆の方がいいだろう。
単純に破棄すると何も起こらず、明示的にポップの指示を出すことでポップが行なわれる、という形だ。
そこにポップができるのは1回だけ、という制限を設けようとすると、メモリ確保は避けられないが仕方ないな。
fg::StateStackに修正を入れた。
*
fg::Stateの初期化をプッシュイベントで処理していたのをやめ、初期化関数を別に用意した。
プッシュイベントは非同期に呼び出されるし、データを1つしか受け渡せなかったため、応用が効きにくかった。
初期化関数はfg::Stateがプッシュされる前に同じスレッドから呼び出され、複数のデータを受け渡せるようにした。
初期化時に渡すデータを変えることで、画面の挙動に変化を与える、ということがやりやすくなったと思う。
画面のコードが固定的になりすぎて、実際の画面の数と完全に同数にコードが必要になりそうなのが気にかかっていたのだ。
*
この修正で、プッシュイベントがポップやエンター、リーブと比べると明らかに異質な存在になっていたのも解消できた。
テンプレートで実装したため、単体で呼び出させたくない関数もできてしまったが、そういう関数は関数名の末尾にアンダーバーを追加した。
多少不自然な感じに見えるので、普通は呼び出さないことが伝わるかもしれない。
fg::StateStackがいい感じ。
*
想像以上にと言うか想定通りにと言うべきなのか、考えたことが実現できているように思う。
単純な画面遷移はもちろん、画面内の状態遷移もfg::StateStackで表現できる。
あるfg::StateStackのイベント関数から、別のfg::StateStackのイベント関数へのイベントの伝播もできる。
名前空間を切り分けることで、現実的なレベルで大規模な開発もできそうだ。
*
using namespaceとか、初めて実戦で使った。
厳密に言えばユニークポインタで使ってるけど、あれはちょっと特殊な状況だし。
きちんと生かせていそうなのは今回が初めてだ。
*
欠点としては、自分で作ったものとはいえ自分自身あまり馴染みのない構成の記述を強いられているようで、すごい不安な気分になってくるというところか。
自分の妄想を形にしただけ、と言っても過言ではないものなので仕方がないことではあるが。
本当にこのままうまく行くのだろうか。
*
例外対応は全くやってないわけだけど、きちんとやろうとすると大幅な修正が必要なのは確実なんだよなぁ。
ネイティブコードである以上、単に例外処理を追加しただけではNULL参照でSEGVで死んでしまう。
それを検知し、取り扱うためにはゲームの処理を別のプロセスで動かす、などするしかないだろう。
chromeなんかではそういった処理がされているようだし、できなくはないはずだ。
しかし自分でやったことはない。
子プロセスから親プロセスにあるウィンドウにOpenGLで描画するとか、できればいいのだが。
やれやれ、少し詰まってた。
*
でもEventProcsをStateに変更するのは完了した。
へびゲームやらも修正して、動作確認まで済ませた。
他にも、後回しにしていた細かい修正を適用したりした。
*
Stateにデータを持たせられるようにしたのは、想定よりもいい感じかもしれない。
今まで、ゲームのデータはfg::GameContextに設定するデータに集約しなければならなかったが、その必要がなくなった。
画面が共通のゲームデータから独立して、新しいものを追加しやすくなったように思う。
*
他に今まで扱いにくかったのは、サブのfg::StateStack、元fg::EventProcsStackだな。
1つの画面内における細かい遷移をうまく表現できるか、明日コントローラ設定画面で試してみる予定。
*
Stateにデータを持たせられるようにした関係で、fg::StateStack破棄時に全てポップする、という処理はもう必要ないのかもしれない。
それが必要だったのは、プッシュ時に確保していたデータをポップ時に解放していたからだし。
今のところは、処理があってもなくても大して違いはないからいいけど、この処理は破棄処理中に例外が投げられる要因になっていて危険なので、不要であると確信が持てたら消そう。
EventProcsの名前を変更する。
*
Stateに変更する。
元の名前は直接的すぎるし、なにより長くてよくなかった。
遅くとも明日中には完了する予定。
で、新たに機能を追加する。
*
EventProcsは名前の通りイベント関数の集まりだったんだけど、そこにデータを確保する機能も付ける。
今まででもPush時にデータを確保し、Pop時に確保したデータを破棄する、というようにして、イベント関数でのみ使うデータを扱っていたが、データ破棄のためにわざわざPopイベントの関数を作ったりするのがめんどうだったのだ。
割と頻繁に必要になるし、だったら機能を追加して破棄くらいは自分でやらずとも自動でやってくれるようにしよう、というわけ。
イベント関数群とデータ、合わせて「状態」と呼べそうなのでStateと名付けた。
*
とはいえ、こんなことに何日も使いたくないので、さっさと終わらせてコントローラの扱いの続きに入りたい。
とりあえず一通り対応。
*
candymaker以外に、karameruやらzarameやらも対応して、cmsnakeも対応して動作確認もした。
しかし、大まかにはいいのだが、関数名はどうにかする必要がありそうだ。
生成関数の接頭辞全てがnewではよくない。
頭にnewが付く生成関数は、nullを返すことがなく、異常時は常に例外を投げることで対応する形にしたい。
つまり、頭にnewが付く生成関数の戻り値はnullのチェックをする必要がない、ということだ。
それ以外に、異常時に例外を投げず、nullを返すこともある関数というのももちろんあるが、そっちは頭にnewを付けない形にしたい。
そうしておけば、関数名で戻り値のチェックが必要なのかどうか判断できる。
*
で、ひとまずkarameruの画像読み込み関数の接頭辞をnewからgenerateに変更した。
fgの方も対応するべきだし、例外対応を考えると戻り値をboolからvoidにしていい関数もある。
しかしこれは今やるべきなのかどうか。
いや、ユニークポインタの変更と比べたら、ずっと楽な修正だからやってしまうべきか。
ユニークポインタの扱いを改善した。
*
本当ならkasuteraを進める予定だったんだけど、ちょっと及び腰になってしまったので。
また、ユニークポインタの扱いは古いものと新しいものが混在する状態になってしまっており、後々のことを考えると先にどうにかしておくべきと思っていたのだ。
*
それに付随して、ユニークポインタの定義を改善した。
これにより、使い勝手がかなりよくなったように思う。
今までは、ユニークポインタを扱うファイルではユニークポインタのヘッダファイルを最後にインクルードしないとコンパイルエラーが起きる可能性があったが、改善によりインクルードの必要がなくなった。
これによりヘッダファイルのインクルード順を考慮しなくて済むようになった。
fg、sucroseについては対応したが、candymakerについてはまだなので、明日やる予定。
*
あまり足踏みしてないで、早くkasuteraを進めないと。
生コントローライベントについて、zarameの方まで対応できた。
*
が、動作確認はまだ。
実際にコントローラを動かさないと確認できない気がするので、自動テストに書けないのがきびしいところ。
明日へびゲームを新しい仕様に合わせて書き換えて確認する。
改良しつつ生コントローライベントをアクションに変更完了。
*
といっても、それらを扱う部分についてはまだ。
なんだか既存の構成をざっと見た感じ、あまり頭のよくない構成になっている気がする。
生コントローラと、その上に来るコントローラの扱いには関係があるからか、同じところで処理しようとしているように見える。
関係性については正しいのだが、だからといって同じところで処理する、というのは間違ってる気がする。
生コントローラの管理とそれを踏まえた上でのコントローラの管理は別々にした方がよさそう。
大体、一緒にしてしまったら肥大化しすぎて手に負えなくなる。
*
後々拡張すること前提の構成もあるようなので、そういった部分を省けばより単純な構成にできそうだ。
明日中には、ゲーム側でイベントが受け取れるようにまで対応したいところ。
メインウィンドウ描画イベント対応完了。
*
古いfg-eventとfg-basesystemeventを削除して、新しいfg-eventのみに差し替えるのも済ませた。
さすがにそれら残したまま対応するのは余計にめんどくさそうだったので。
描画イベントの対応も、想定通りにできたと思う。
コントローライベントに関しても、同じようにやれば問題なくできそう。
*
新しく追加する型については、生成処理の書き方を多少変更している。
例えば、後々例外対応することだし、ということでnewする時にstd::nothrowを付けて戻り値をnullチェックする、というのをやめたり。
生成した型のユニークポインタを得るためにfg::unique( fg::newData() );みたいな書き方をしなくても、fg::newData();でユニークポインタが返るようにしたり。
ほぼ確実にユニークポインタを使うのに、毎回前者のような書き方をするのは面倒だったのだ。
それによって多少問題が起きているが、致命的ではないしそのうち対応する予定。
先週中に片付けるつもりだったが、今日までかかった。
*
というわけで、新しいfg::EventProcsStackはできた。
fg::BasesystemEventProcsStackを排除した構成なので、ソースの量は1/3くらいになった。
しかしまだ全部ができているわけではない。
ベースシステムへの登録機能がまだ。
*
登録処理の実装はベースシステム内だけど、それ以外の部分をどうするべきかがまとまっていない。
具体的には、イベント関数呼び出しとイベントデータ。
各ライブラリ内でいいか、と思ったら今度は別の問題が出てきた。
コントローライベントは型の名前が重複してしまうのだ。
コントローライベントはコントローラの接続・切断やボタン押下などで発生するが、実際に使う上ではどうせどっかのバッファにまとめてから使うわけだし、とそういった処理もライブラリ内で行なっている。
ゲーム側から見た時にコントローライベントから得られるのは、直前までに溜め込まれた複数のイベント群となる。
なので、fg-basesystemeventにfg::BasesystemRawControllerEvent、fg-controllerにfg::RawControllerEventが配置されており、前者の中に後者が複数含まれる形になっている。
しかしこれだと、1つにまとめてBasesystemという文字を取り外すと名前が完全に一致してしまうのだ。
*
よく考えたら後者、fg::RawControllerEventのEventというのは正しくないのではないだろうか。
今の構成において、Eventというのはfg::EventProcsに設定し、呼び出されるものだ。
そう考えると、fg::RawControllerEventはそれに当てはまらず、ふさわしくない。
別の文字に置き換えた方がよさそうだ。
で、考えたのはAction。
ボタンアクション、コネクトアクション、アクシズアクション。
正直イベントの方がしっくり来るが、変えなければならないのだから仕方がない。
もっとふさわしいのを思い付けばそっちにするんだけど。
*
コントローラの方をやる前に、まずウィンドウ描画の方をやってしまう方がいいかもしれないな。
こっちはイベントデータから何か取り出すとかは今のところないし、コントローラの方よりずっとシンプルなのだ。
ウィンドウ描画の方を先に作って実際に動かし、確証が得られればコントローラの方も取りかかりやすくなるし。
fg::EventProcsManagerが余計かもしれない。
*
fg::EventProcsManagerはfg::EventProcsStackへのプッシュ、ポップを行う型で、破棄時には生成時の要素数になるようにポップする機能があり、整合性を崩れにくくしている。
が、その破棄時の動作が正常に動作していない。
fg::EventProcsStackに追加されているイベント関数からfg::EventProcsManagerの破棄が行なわれるとデッドロックしてしまうのだ。
*
根本の構成的には、ポップするだけであればポップのリクエストと処理は非同期に行なわれるため、イベント関数中でポップのリクエストがあったからと言ってデッドロックは起きない。
しかしどうにもfg::EventProcsManagerの存在が邪魔なようだ。
fg::EventProcsManagerは整合性を保つため、プッシュやポップ時に要素数を確認し、生成時の要素数未満におけるプッシュや、要素数未満になるようなポップは禁止している。
要素数確認のためには排他ロックをかける必要があり、それが競合を起こしているのだ。
と、思っていたのだけどデバッガを使って詳しく調べたらちょっと違った。
破棄時の要素数を合わせるポップのリクエスト後に、その処理が完了するまで待機しているのが問題のようだ。
イベント関数からの呼び出しで待機してしまうと、ポップ処理で行なうロックを保持したままになっているのでデッドロック。
とにかく、現状ロックしすぎててよくない感じ。
*
fg::EventProcsManager破棄時のポップリクエスト後、ポップ処理が完了するまで待機する、というのはベースシステム内のfg::EventProcsStackから破棄済みのゲームデータへの参照が起こらないようにする対処だったんだけど、やはりその場しのぎだったか。
ゲームからなんの干渉もなく、ベースシステムからゲームへの参照が存在してしまっているのを、まずどうにかするべきなのだ。
例えば、fg::EventProcsStackはゲーム内で生成し、それをベースシステムに登録する形にする、とか。
当然、破棄もゲーム内で行なうので、ゲーム破棄後にベースシステムからゲームへの参照は起こらない。
*
fg::EventProcsManagerの代替については、プッシュ時にポインタを返すようにし、それを破棄することでポップが行なわれる、というのを考えている。
しかしそれだと、うっかり戻り値を拾い忘れたら大変な気がする。
そんなこと言い出したら、今ある生成関数は全部そうなんだけど。
つまり、その辺も対処が必要かも。
生成関数はユニークポインタを返すようにして、戻り値を拾い忘れても自動で破棄されるようにする、とか。
*
なかなかひどいけど、動かないことはないしなぁ。
後回しでもいい気がする。
あーあと、例外対応とログ出力もどうにかしたい。
やるべきことは多いが、その全てを今やるわけにもいかない。
コントローラ設定画面を作る上で直接関わってくるのは、やはりfg::EventProcs周りか。
fg::EventProcsStackとfg::EventProcsManagerをペアで使えば、現状でもとりあえず動くものができるし、それでやろうかなぁ。
*
いや、やはりfg::EventProcsManagerを除外した構成に変更するべきか。
現状のfg::EventProcsManager破棄時の動作は、fg::EventProcsStack破棄時に行なうようにすればいい感じにまとまりそうなのだ。
それに、ベースシステムにfg::EventProcsStackを登録する形にする際にも役立ちそうだ。
登録型にできれば、fg::BasesystemEventProcsの排除ができるかもしれない。
kasuteraの開発を進めようとして、ちょっと行き詰まっている。
*
タイトルロゴのようなものを出した数秒後にメインメニュー画面に遷移する、という流れは問題なく書けた。
タイトルロゴ画面とメインメニュー画面は別のソースファイルに分離できており、分かりやすい。
問題はここからで、メインメニューを操作するためにはコントローラ設定が必要であり、その初回の処理をどう作ったものか。
前に作った暫定的なものは画面が付いてないし、画像を扱えるようになったのでそれを利用した形にしたいが。
*
で、その辺もやもやしててどうにも手を出しにくいので、tafの改修をしていた。
今までは一応自動テストとかできてたけど、実際に使用する生成物やテストが混在しており、扱いにくかった。
試運転するにも、モジュールのファイル1つ1つにシンボリックリンクを張らなければならかなったり面倒だった。
そこで、テストとそれ以外の生成物を別のディレクトリに出力する形にして整理した。
ただ、この形にするならコンパイラで生成するファイル以外にも、例えばパッケージファイルも生成物のディレクトリにコピーしたい。
そういう機能は、既存のものをちょっと変えれば対応できそうだがまだないので、明日対応する。
*
コントローラ設定画面はいまいちどうしたらいいか分からないと言っても、とりあえず作らないことにはどうしようもないことも確かなのだ。
未知の領域なので、おおまかにどういったのを作りたいというのがあっても、それを最初から的確に作るのは難しい。
とりあえずなんでもいいから作って、そこから目的の形に寄せていくしかない。
PNG画像の対応完了。
*
想定よりもフォーマットの数が多く苦戦したが、苦労の甲斐あっておそらく全てカバーできたはずだ。
libpngにはインデックスカラーをRGBに変換する機能があったので、それを使ってインデックスカラーにも対応した。
libpngもlibjpeg-turboと同じく、エラーの処理にsetjmp()を使う必要があるが、libjpeg-turboに比べればずっとましな気がする。
何もしないとエラー時に勝手に終了してしまうのは同じだが、libpng自体がjmp_bufを使った構成になっていて、setjmp()を呼び出すだけでエラー時にlongjmp()で飛んでくるようになり、勝手に終了することはなくなる。
png_structとpng_infoはそれぞれ別の関数で生成するのに、破棄は1つの関数で同時にするのがちょっと気持ち悪い、くらいか。
*
JPEGとPNGに対応したので、karameruはこれでv1.0.0とした。
画像を手軽に扱えるようになったので、これでkasuteraの開発に入れるかな。
JPEG画像の対応完了。
*
JPEG描画テストの、ライブラリを直接叩いてJPEG画像を読み込んでいた部分を差し替えたら70行ほど減っていい感じ。
その上、グレースケールにも対応。
ビルドしなおすことなく、読み込むファイルを変えるだけでカラーとグレースケールとも描画できることを確認した。
カラーとグレースケールではフォーマットが違うが、fg::GLPictureの機能でそれに対応できていていい感じだ。
*
今回libjpeg-turboを使用したが、なかなか動作が気持ち悪くていやな感じ。
インターフェースがlibjpegのものを踏襲していると思われる?から仕方ないんだろうか。
エラー時、何も対応しなければexit()で勝手に終了してしまったり。
対応しようとするとlongjmp()を使ってエラー関数から元の関数までジャンプしなければならなかったり。
その対応をするためのテスト用データとして、正常系で使っていたJPEGファイルを真っ二つにしたものを用意したのだが、なぜかそれを使ってもエラー扱いにならなかったり。
その不正データはどこで不正と判断すればいいのかと色々いじくった結果、警告が発生するのでその回数をチェックすればいい、というのは分かったが、いじくってる過程でエラーメッセージ出力用関数を自前のものに変更していたら、警告回数が増えなくなっててチェックに使えなくなっていたり。
ちなみに、何も対応しないとエラー時に勝手にexit()する挙動については、JPEGではないデータを読ませることで起こせる。
その程度で死なないでほしいんだが。
*
明日はPNGの対応を追加する予定。
JPEGとの違いは、とりあえずはアルファ値か。
あとはインデックスカラーというのもあるけど、こっちはひとまず後回しにする。
まだ扱い方を知らないので、やりようがないのだ。
インデックスカラー自体は、メモリ使用量削減とかパレット変更による色変えとか、ゲームに向いた特性を持っているので扱えるようになりたいところだ。
*
この前の休みに、tafにPSPで動作するプログラムやプラグインのビルドルールを追加した。
といっても、自動テストも作ってないしEBOOT.PBPは1プロジェクトにつき1つしか作れないし、リビルドには1回クリーンしなきゃならないなどなど、問題だらけで突貫工事もいいとこだが。
ひどい状態だが、とりあえずビルドしたものが動くのを確認できたし、makeとかいうクソビルドツールを使わずにプラグインを作れるようになったわけで、空いた時間に色々いじっている。
RemoteJoyLiteのソースらしきものをどこからか落としてきて持っているので、それを見ながらUSBの扱い方を調べているのだが、やはりというかなかなかひどいソースだ。
特に意味もないのに配列でデータを持っているなんてのはまだましだが、初期化時に一時的にしか使わないデータがなぜかグローバルに置かれてるのはちょっとなぁ。
USBの停止?関数はあってもどこからも呼び出されてなかったりもする。
C言語だから仕方ない、というのもあるのだろうが。
画像データを扱うためにfg::GLPictureを追加した。
*
汎用的なものにしようかとも考えていたが、まずOpenGL以外では使わないだろうし、OpenGLに特化したものにすることにした。
画像だからfg::GLImageの方がいいかと思ったが、OpenGLの関数にglImageなんたらというものがあったし、混同しないようにOpenGLの関数には存在しない単語を選んだ。
*
JPEG画像の読み込み処理はちょっと前に書いたし、先に作ろう。
その次にPNG画像読み込み処理を作る予定。
とりあえずはその2つがあればどうにかなるだろう。
むしろPNGだけでいいのでは、という気もするが。
管理画面の名前はkasuteraとした。
*
画像読み込みライブラリの名前はkarameru。
名前は決まったが、具体的に読み込んだ画像データをどのように型で扱うのかが定まっていない。
どうしたものか。
*
画像を読み込む前に、パッケージのリソースにアクセスするためのインターフェースを復旧した。
復旧した上で、今までよりもアクセスしやすい形に関数を追加した。
これで画像ファイルの読み込みもやりやすくなった。
いよいよ画像データの扱いについてまとめなくては。
*
どうにも体調が優れない。
季節の変わり目のせいだろうか。
気温の変化が激しくて困る。
土日はまた暑いらしいし。
sucroseのベースシステムをzarameとして分離完了。
*
これでベースシステムの内容を詰めやすくなった気はする。
他のモジュール、例えば画像を扱うものとかを使いやすくなったし。
しかしそれは今やることではないだろう。
*
というわけで次はどうしよう。
コントローラの扱いとかも確かに重要なんだが、それよりもメインメニュー画面というかランチャーというか、導入済みのゲームの起動、管理とか、コントローラの管理とか、そういった機能にアクセスするためのものを作るべきではないか。
なんというか、それがないと始まらん気がするし。
そろそろその辺りに手を出してもいいくらいには、機能も整ってきたように思う。
まず名前を考えないといけないな。
fg::BasesystemEventProcsManagerで発生していた問題を修正した。
*
で、次に何をやるというか、そもそも何のためにCoreManagerとか作ったんだっけ、というのが朧げだったので過去の記事見たら書いてあった。
zarame…そんなのもあったな…。
ゲームから別のゲームを起動する機能については後回しでいい。
ベースシステムの独立に当たり、気掛かりなのはbasesystemeventか。
ベースシステムから分離はさせたものの、ベースシステムとの繋がりが強すぎる。
できることならfg::BasesystemEventProcsとか作らず、全部fg::EventProcsで済ませたいが、それでうまくいきそうな案が出てこない。
それができれば、fg::BasesystemEventProcs前提の構成になってるfg::EventProcsの実装をもっと単純にできるのだが。
*
とりあえずは、sucroseからベースシステムをzarameとして別のプロジェクトに分離するか。
candymaker::CoreManagerの追加完了。
*
ゲームの稼働を確認し、余分な関数の削除、その代替機能の追加、不要になったファイルの削除まで完了し、バージョンも確定させた。
しかしながら、sucroseで一部テストが通ってない部分がある。
ゲームの稼働で問題は起きてないとはいえ、少なくも1つはNULLポインタの参照なので解決しておきたい。
想像よりも大幅に時間がかかっているが、終わりは見えてきた。
*
残件は余計に追加してしまった関数の削除、その部分の代替機能の追加、不要になるファイルの削除、か?
来週中にはゲームが稼働できることを確認したい。
で、不要なファイルを削除してバージョンを確定させたい。
明日一杯使っても難しいかもしれない。
*
やる気がびみょうというのも大きいけど、sucroseのベースシステムに内包する要素を全て修正する必要があるのがきつい。
1つ1つ地道に修正していくしかないが、構成が変化しているため単純な修正で対応できるのかどうか。
想定では、今までfg::BasesystemContextの参照を引数に含んでいた関数を、fg::GameContextの参照を引数に含むものも用意することで対応できそうな気がするが。
*
今までfg::BasesystemContextの参照を用いていたところを、sucrose::Basesystemの参照に変更する。
sucrose::Basesystemの参照はfg::BasesystemContextかfg::GameContextから取得できるので、両方用意しておけば問題ない、といった具合。
しかしfg::BasesystemContextの参照を用いる関数は、fgに追加するべきか、sucrose内の仕様に留めるべきか。
現状ではどちらでもよい、と言わざるを得ないな。
ゲーム側から使用することはまずないことを考えると、sucrose内の仕様に留めておくべきかもしれない。
candymakerの処理を、candymaker::CoreManagerを使ったものに切り替えた。
*
これがきちんと動作するか確認するためには、sucroseのベースシステムを新しい仕様に対応させる必要がある。
起動するゲームについても同様だ。
とはいえ、ベースシステム内の処理内容は基本的にいじくる必要はないし、明日中、ないしは今週中に対応して確認したいところ。
確認が取れたら、古い仕様や間違って追加してしまった機能の削除だ。
よくない感じがする。
*
fg::BasesystemContextの参照を用いて行なっていた操作について、対応できるようにしていたが、対応を間違えた感触がある。
fg::BasesystemContextの初期化時に関数ポインタを設定し、fg::GameContextの参照を経由して設定した関数を呼び出す、という仕組みにしているが、fg::GameContextの参照を経由する必要があるのかどうか。
そもそも、fg::BasesystemContextやfg::GameContext自体に機能を追加するというのが間違っている気がする。
そういったものに対する操作というのは、厳密にはそれ自体ではなく、それらが抱えているデータにアクセスできればいいのだ。
実際、そういった方法で動作している機能もある。
分離しにくいから、というだけでfg::BasesystemContext自体に機能を置いてしまっていたのが否めない。
*
なので、fg::GameContextやfg::BasesystemContextからは、データの取得だけできる形に変更し、抱えてるデータを扱う処理はcandymakerに完全に含めない形にするべきだろう。
先週末までに起動処理作り切りたかったけど、無理だった。
*
で、今日出来上がった。
モジュールもベースシステムもゲームも、設定可能な関数は初期化関数のみになり、いい感じ。
ただ、fg::GameContextを作った関係で、今までfg::BasesystemContextの参照に対して行なっていた操作の一部は、fg::GameContextからfg::BasesystemContextを参照しないと動作できなくなってしまっている。
その辺り作っていかないと。
でもまぁ、fg::BasesystemContextの初期化時に関数ポインタを設定できるようにして、fg::GameContextからその関数にアクセスすればできると思うし、難しくないはずだ。
やっとcandymaker::ModuleManagerができた。
*
モジュールのロード以外に、モジュールの不要判定、不要になったモジュールのアンロードやロード中のエラー対応など、必要になる機能を色々と追加した。
ただ、今のままでは複数のモジュールの生成・破棄処理のペアリングがされていないので、その対応のためにもう1つ型を作るべきかもしれない。
そこまで済めば、ベースシステムの対応に入れるか。
*
candymaker::BasesystemInfoは必要ないかもしれない。
単に、それに含める予定だったものを、ベースシステム生成時に引数として渡す。
まとめて扱う意味があまりなさそうなのだ。
今回作ったcandymaker::ModuleManagerでロードするモジュールの情報はcandymaker::ModuleInfoという型にまとめたが、それは一度に複数のモジュールをロードするために、モジュールの情報をまとめる必要があったからだし。
ようやくどうにかなるかもしれない。
*
目的、つまり関数の動作と、そのために必要なもの、つまり関数の引数を、もっと明確にするだけでよかったのだ。
ベースシステムの起動という目的を達成するためには、ベースシステムを構成するモジュールのロードと、イニシャライザの実行が必要だ。
なら、引数はロードするモジュール群の情報と、イニシャライザのシンボル名だ。
それらをまとめて、candymaker::BasesystemInfoとしよう。
candymaker::BasesystemInfoは、少なくとも初回の起動においては、ショートカットファイルを解析して生成する。
その過程で、パッケージ情報ファイルや設定ファイルを読むことになるだろう。
*
いままでの構成では、モジュールのロードは外部で済ませており、ベースシステムの起動処理はイニシャライザの実行だけだったが、これはよくない。
モジュールのロードは必要に応じて行なわれるべきものであり、それを目的の外でやってしまうのは、なんのためにモジュールのロードが必要だったのか、という関連付けを薄くしてしまう。
そうなると、後から見返した時に処理の意図が読みにくくなる。
*
その辺の意味では、現状のモジュールロード周りもよくないな。
パッケージ設定ファイルを解析したものをそのまま渡したりしている。
具体的に何が必要なのか、引数を明確にするべきだな。
新しく作る方には、candymaker::ModuleInfoとかいう型でも作って、そこに必要な情報をまとめるか。
とりあえずパスについては完了。
*
今までは○○Refという型名だったが、○○Pathに変更にした。
また、dataelementからデータを取り出し生成する形だったものをやめた。
その辺の処理はファイル解析側にまとめることにした。
*
ショートカットファイルの読み込みと解析をするためには、あとはファイル読み込み処理の移行が必要なぐらいか。
dataelementについては、ひとまず今存在するものをそのまま使う。
まだかなりぼんやりしている。
*
アイデアは出てくるのだが、まとまりはいまいちだ。
fgのインターフェースのうち、candymakerで実装するべきものはfg-coreにまとめるとよさそう。
現時点で対象となっているのは、fg-dataelementとfg-module。
新たに追加するfg::GameContextとfg::BasesystemContextも含まれる。
*
パッケージマネージャが必要と言ったが、実際にはもっと広い範囲をカバーしないとだめだ。
具体的には、稼働しているベースシステムやゲームも含む、ということだ。
candymaker内のfg-coreと関わりが深くなりそうだし、candymaker::CoreManagerという名前にしようかと考えている。
candymakerの起動と同時に生成し、破棄と同時に終了する。
今の仕様ではコマンドライン引数を元にベースシステムやゲームを起動する、という形だが、将来的にはコマンドライン引数が渡されなかった場合はデフォルトのベースシステムやゲームを起動するようなこともさせたい。
*
fg::BasesystemContextがありなら、fg::ModuleContextもありだろう。
これまたすでにその名前の型はあるのだが。
現時点ではモジュールの初期化と終了で2つの関数が必要だけど、fg::GameContextに倣う形にすることで初期化関数1つだけで済む形にする。
そのようにしたら、ゲーム、ベースシステム、モジュールの各初期化関数は、固定のシンボル名じゃなくていい気がするな。
過去にそうしていたように、設定ファイルにシンボル名を記述する形にしたい。
*
とりあえず、candymaker::CoreManagerを作っていこうと思う。
ベースシステムやゲームの生成に必要なので、これを作らないことにはどうしようもない。
モジュールの読み込み処理などの既存の記述は使うが、ファイルの位置を変更する予定。
その過程で、型の名前とか変えたりするかもしれない。
fg::GameContextと同じように、fg::BasesystemContextも用意するべきか。
*
その名前の型はすでにあるんだけど、それとは違う。
すでにあるfg::BasesystemContextはベースシステム本体を表している。
今回考えたfg::BasesystemContextは、ベースシステムのデータを管理するための型だ。
fg::BasesystemContextの実装はcandymaker内に用意し、ベースシステム本体はfg::BasesystemContext内のデータ領域内、という形になるわけだ。
これがあることで、今はベースシステムの生成と破棄、2つの関数をdlsym()で取得しているが、それが初期化関数の1つで済むようになる。
*
などということを考えたが、いい加減妄想膨らませるだけでなく作業をしたいところだ。
どこから手を付けるべきか、難しい。
大きく分けて、ベースシステム起動処理と、ゲーム起動処理を修正する必要がある。
ベースシステム起動処理の変更は、ゲーム起動処理にも影響を及ぼす。
しかし、ベースシステム起動処理の変更の影響を、古いゲーム起動処理に適用するのはいらない手間な気がする。
そう考えると、まずゲーム起動処理を修正するか。
パッケージマネージャーだな。
*
ベースシステムからの、必須機能以外の独立はすでに済ませた。
ゲーム起動インターフェースをfgに追加するに当たり、イメージがぼんやりとしていてまとまらず、手を出せないでいた。
モジュールの管理機能をベースシステム内に配置するわけだし、ベースシステムの関数としてゲーム起動関数を用意しようかと考えていたが、それは変だ。
それだとベースシステム内にゲーム起動機能が存在することになる。
モジュールの管理機能自体はベースシステムの外に用意し、ベースシステム内には参照だけ配置するのだから、ならゲーム起動関数もベースシステムの外にあるべきだ。
で、ゲームを起動するに当たっては、設定ファイルも読める必要がある。
単に読むだけでなく、どの設定ファイルによってどのモジュールを読み込んだかなど、管理機能もあった方がいい。
*
できればsucrose内に配置したいところだが、candymaker内になりそうな気がする。
とりあえずタスク処理について独立させた。
*
次はベースシステムのイベント処理だ。
しかし、構成を何も変えず独立させたので、いまいち作りがよくないように見える。
後々、その辺変えるべきか。
ベースシステムの生成はいいが、ゲームの起動処理をどうするかよく考えるべきだな。
*
少なくとも、現在の構成ではゲーム中から別のゲームを起動する、ということができない。
それをするには、ゲーム側でパッケージや設定ファイルを読める必要があるわけだが、それがないからだ。
つまりfgにそれらのインターフェースを追加する必要があるわけか。
かなり大変そうだし、後回しにしたいなぁ。
*
zarameを進めたかったが、そう考えると無理だな。
ベースシステムに必須ではない機能を別のモジュールに分ける、の方が先か。
sucroseのベースシステムを独立させたもの、これをzarameとする。
*
プロジェクト名も決まったことだし、今日中に準備を済ませて明日から本気出す。
最近、気温の変化が激しすぎるためか体調が優れない。
*
そのせいもあり、やる気もうまく上がらない。
来週もこうだと困るなぁ。
せめてどこから手を付けるかだけは、今のうちにきちんと決めておこう。
fg::GameContextを作るべきか。
*
少なくとも今の設計では、ゲームから別のゲームを呼び出す、というのが困難に思える。
別のゲームを呼び出し、終えたら元のゲームに戻る、というような動作をするためには、元のゲームの状態を保持しておく必要がある。
今のところ何が必要なのかまだもやもやしているが、少なくともfg::EventProcsManagerは持っておく必要があるな。
正確にはfg::BasesystemEventProcsManagerか。
あとはゲームのデータも、今はcandymakerの関数内ローカル変数に1つだけだが、fg::GameContext内に持たせるべきだろうな。
そうなると、ゲームの初期化や終了関数の構成も変わってくる。
とりあえず、fg::BasesystemContextと似た機能を持った型は必要だろうが、それをゲーム側から直接参照できる必要はない気がする。
fg::GameContextの参照を引数に持つ初期化関数だけでいい感じか。
現状、終了関数とかfg::GameDataのdeleteしかしてないし、おまじないじみたコードが減るのはいいことだ。
その代わり、ベースシステム側は機能が増える。
fg::BasesystemContextの参照を引数にfg::GameContextを生成する関数は必要になるだろうし。
*
ベースシステム本体の独立と合わせて、その辺も改良していきたいところだ。
ベースシステム本体はsucroseから切り離すべきかもしれないなぁ。
*
そこ以外は、完全にただのライブラリなのだ。
しかしベースシステムは画面の表示などのために画像や音声などのリソースも必要になる。
そういったものが純粋なライブラリ内に混在してるのは違和感がある。
現状のベースシステムには、タスクやイベントの管理などがまとめられてしまっているので、それらを独立させ、ベースシステムはそれらを外部から利用する形にした方がいいかも。
*
今想定している作りとしては、以下のような感じ。
・基本インターフェース定義(fg)
・基本インターフェースを持つライブラリ(sucrose)
・基本インターフェースを持つベースシステム
・基本インターフェースを持つゲーム
・基本インターフェースを持ったベースシステム上でゲームを動かすプログラム(candymaker)
ベースシステムやゲームは、sucrose以外にも画像や音声の処理を行なうライブラリも利用する形になる。
そっちはそっちで、基本インターフェースからは外れるライブラリを用意する。
ベースシステムも、インターフェースが異なるだけでどちらかと言えばゲームに近いのだ。
だからゲームと同じように独立させるべきだと思う。
*
しかしながら、ベースシステム側では必要でも、ゲーム側では必要ないインターフェースも多くある。
ベースシステムは基本インターフェースにだけ依存させるのではなく、ライブラリに依存させた方がいいかも。
とりあえず、あとはサンプラのリソース管理だけ。
*
可能な部分は、より機能を簡単にしたバインダーも作るけど。
この次何を進めるべきか、考えておかないといけないな。
OpenGLのバージョンの管理というか、特定のバージョンで扱うと決めたら、そのバージョンには存在しない関数は呼び出そうとしてもコンパイルエラーになるとか、そういった機能も追加したいが、それは緊急でもないし。
…自分で作った方が早いかもしれない。
*
livedoorブログやらBloggerやらで、今のこのサイトみたくスタイルシートとかまるで使わんシンプルな表示にしようとしても、テーマいじくるのが非常にめんどくさい。
ブログ自体にどういった機能があるのか、何ができて何ができないのかについてもいまいち分かりづらい。
スタイルシートを全く使わんようにすると、コメントとかその辺の機能に支障が出るようだし。
デフォルトのテーマのまま使えばいいんだが、気が乗らない。
で、既存のよくあるシステムとは一線を画したシステムを作ってみるのもいいかなーという気もしてきている。
やるんなら休日だけど。
*
平日の作業とは関係ないことに時間を使いすぎた。
VAOやらシェーダやらのリソース管理のための型を追加するとしよう。
VAO便利だな。
*
VAOを使わない場合、VBOやIBOを1つずつバインドしたりする必要がある。
VAOを使えば、それらは事前にしておき、描画時にはVAOをバインドするだけで済む。
気掛かりなのは、VAOにIBOを含められるのかどうか、という点だ。
個人の解説ページでは、含められると書いてあるところもあれば含められないと書いてあるところもある。
実際に試し、可能であることは確認したのだが、本当に正しく機能を扱えているのかどうかはあまり自信がない。
もしかしたら、含められないというのは古いバージョンの話で、新しいバージョンでは含められるようになった、ということかもしれない。
あるいは、全く別の機能で実現できている可能性もないではないだろう。
公式の情報が欲しいところだ。
*
OpenGLのリソースについて、バインド状態をRAIIで管理するのは困難を極めるのではないかと思えてきている。
テクスチャのバインドについては前に書いた通りだが、バッファのバインドの方はきっと問題ないだろうと思っていた。
が、VAOを使う場合、VAOにIBOの設定を登録するには、VAOをバインドした後にIBOをバインドし、IBOのバインドを解除せずにVAOのバインドを解除する必要がある。
VAOのバインドを解除した後にIBOのバインドを解除する、というのは違和感がある。
VAOをバインド中にバインドしたIBOとは別のもののバインドを解除してしまう、つまり整合性が取れてないように思うのだ。
VAOに対してはIBOはバインドしっぱなしにする必要があり、あえて解除するというのであれば、別のIBOに変更する時とか、VAOを破棄する前とかそのくらいだろう。
バインダなんていうのは、きちんとやろうとすると複雑になりすぎるので、作らない方がいいかもしれない。
*
いい加減、ブログを借りようかと考えている。
月や年ごとにページ切り分けるのが面倒になって、3、4年ほどの内容が1つにまとまってしまったが、HTMLの行数にして5000行以上あり、vimで編集しているとちょっともたつくことがある。
文字に様々な装飾を施すだの、リンクを張ったりなどということはほぼしないため、タグ直打ちでもそれほど作業負荷は高くないのだが。
昔であれば、じゃあそういうシステムを自分で作ろう、とかとち狂ったことを考えるのだろうが、今はもうそんな無駄なことはしたくない。
きちんと作るとなると手間がかかりすぎるし、その手間をかけてやっとできる、というよりそれよりもよいシステムが借りられるなら、それを使えばいいのだ。
ライブドアとかそのへんのブログを借りてみようかなぁ。
PSPのプラグインを作りたくて、色々いじくっていた。
*
完全に趣味なので平日はやらない。
外部コントローラでPSPを操作できるようにしたいのだ。
そのような機能を持ったプラグインはすでに存在するが、raspberrypiにPSPとUSBコントローラをつないで操作する、という条件下だとうまく動くものはなかった。
で、あるかも分からないものを探すよりも自分で作った方が早い、ということだ。
幸い、PSPの開発環境についてはプラグインを探す過程でソースからビルドしたりすることもあったのですでにある。
が、1から作ったことはなかったので、今日はHello, world!!と画面に表示するプログラムを作り、いじくったりしていた。
*
ネット上に転がっているサンプルソースは、スレッド処理のくせに排他制御していない無茶したソースだったり、色々試して分かったがそもそもスレッド作る必要なかったりと色々ひどかった。
ゲーム終了のコールバック関数を呼び出すためのスレッドとか、作る必要はない。
main()でコールバック関数を登録し、sceKernelWaitSemaCB()で待機すればいい。
コールバック関数内でsceKernelWaitSemaCB()の待機に使っているセマフォを操作してやれば完璧。
第一、スレッドで待機してるサンプルソースではsceKernelSleepThreadCB()で待機してるけど、それを起こす処理やスレッドの終了、破棄といった処理が全く書かれていないのだが大丈夫なのだろうか。
パソコンのデスクトップOSみたく、PSPのそれもプログラム終了でそれに関連したリソースは全て破棄してくれるようなきちんとしたものなのだろうか。
正直に言えばパソコンのデスクトップOSについてもその辺は伝聞なので、具体的にどうなってるのとか全然知らないんだけど。
*
C++でも書けるようなので、std::unique_ptrを使ってスマートにリソース管理したプログラムを作ろうと思う。
昨日は朝までがんばって、プログラマブルシェーダを使った描画テストを作っていた。
*
がんばっただけあって、なかなかの成果が得られた。
一番のやらかしは、uniform変数の位置取得関数を間違えたこと。
in変数と同じようにglGetAttribLocation()で取得しようとして、うまくいかんなーってのを30分くらいずっとやってた。
uniform変数に対してはglGetUniformLocation()を使わないとだめ。
当たり前と言われればそれまでなんだが。
*
テクスチャバインダは役に立たない、というより設計がOpenGLの仕様と噛み合ってないようだ。
3Dはまだあまり詳しくないので、マルチテクスチャとか知らなかったのだ。
glActiveTexture()でアクティブにしたテクスチャユニットに対し、glBindTexture()でテクスチャをバインドする。
それにより、複数のテクスチャをかけ合わせた描画ができる。
そんなものの存在を知らなかったので、私が作ったテクスチャバインダは同時に1つのテクスチャしかバインドできない。
*
私の作ったバインダというのは、用が済んでもバインドされっぱなしなのは気分が悪い、というのを解消するために作った。
破棄時に、初期値にバインドし直してバインド状態を解除するのだ。
リソースの生成・破棄と違い、そんなに神経質になることはないとは思う。
しかしながら、バグの温床になりそうな気がするのも確か。
形を変えて使いたい気持ちはある。
ちなみに、現在の実装ではバインダを生成・破棄すると見せかけて、生成時にはバインド成功時に引数で渡したコンテキストの参照をキャストして返すだけ、破棄時にはコンテキストの参照にキャストし直してバインドを解除するだけであり、newやらdeleteやらはしていない。
テクスチャユニットを考慮した実装にするとなると、コンテキスト以外にテクスチャユニットについての情報を格納する必要があるから、どこかにその領域を確保する必要があるなぁ。
*
シェーダとはまた別に、思い付いて試した結果、ウィンドウとOpenGLコンテキストの関係も見直した方がいいかもしれない。
1つのウィンドウと2つのOpenGLコンテキストを用意し、片方のOpenGLコンテキストで描画後、もう片方に切り替えて描画、そして表示、という処理を試したところうまくいった。
後の方の描画処理で透過処理を試してもうまくいく。
今まであまり考えたことがなかったのだが、描画データはウィンドウ側が持っているんだな。
当たり前と言えば当たり前なんだけど。
ゲーム側で描画したゲーム画面の上に、管理側が管理情報を上書きして表示、というようなことをする場合、それぞれOpenGLコンテキストを別々に持っていた方がうまく行く気がする。
1つしかない場合、ゲーム側が関知しないところで管理側に違うテクスチャをバインドされて、ゲームの表示がおかしくなった、とかそんな感じのことが簡単に起こりそうだ。
現状では、OpenGLの描画をスレッドで行なうためのfg::GLTaskというものがあるが、これはウィンドウとOpenGLコンテキストを1対1で扱っている。
複数のコンテキストを使い分けるようなやり方をするのは困難だ。
最終的にバッファをスワップするのに使うコンテキストは固定で構わないと思うし、その辺りの作りは現状のままでいいだろう。
ただ、描画処理の引数でカレントコンテキストの参照を渡しているのは間違いだな。
渡すのはせいぜいウィンドウの参照…と思ったが、コンテキストのメンバにウィンドウの参照があるから、カレントコンテキストの設定にウィンドウの参照はいらないんだった。
現状ではカレントコンテキストを生成→カレントコンテキストの参照を描画処理に渡して描画→バッファをスワップ、としているが、描画処理→カレントコンテキストを生成→バッファをスワップとすべきか。
*
最後の件に関しては、早急に対応するべきだろうな。
管理側のOpenGLコンテキストをゲーム側から参照できるようにする必要がなくなるということなので、その辺りにも修正が必要になりそう。
バッファの管理できた。
*
JPEG描画テストで使ったところ、ソースが100行ほど増えたが仕方がない。
元のソース、バッファのバインド解除どころか破棄もやってない手抜き具合だったし。
むしろその辺きちんと加えても100行程度の増加で済んだことを評価したい。
*
とりあえずここで一旦バージョンを確定させて、次はプログラマブルシェーダとか用いたOpenGL3以降の書き方でJPEG描画テストプログラムを作る。
それでどういった要素が必要なのか把握してから、管理機能の追加をしていこう。
*
ちなみにテクスチャやらバッファやらの管理を作ったと言ったが、完全に網羅できているわけではない。
バインダは機能が限定的だ。
テクスチャはGL_TEXTURE_2Dのみ、バッファはGL_ARRAY_BUFFERとGL_ELEMENT_BUFFERの2つだけ。
今のところ必要だったのはそれらだけだったので仕方がない。
最終的には全て対応するべきだと思うが、既存のものを参考にすればぱっと作れるはずだ。
OpenGL2でも、VBOは扱えるんだな。
*
JPEG描画テストの描画をVBOで行なうように変更し、バッファの管理についてはほぼテクスチャの管理と同様の構成で作れるのは把握した。
明日中に作ってしまいたいところ。
それが済んだら、JPEG描画テストプロジェクトをコピーして、OpenGL3を使った描画のテストプロジェクトを作ろう。
テクスチャバインダ完成。
*
作った処理を使ってJPEG描画テストを修正したら、ソースが100行ほど少なくなった。
大体どのような構成で機能を作ればいいか分かってきたし、OpenGL3で使うバッファやら、サンプラ?やらも追加していくとしよう。
テクスチャの件についてはなんとかなった。
*
一度作ったテクスチャを削除した場合、glGetTexImage()でデータが取得できないのを利用することで、テクスチャの破棄についてのテストを書くことができた。
しかし、windowsでも同じような挙動をしたのには参った。
まさか、あんなくそみたいな動作が仕様通りだとでも言うのか。
*
とにかく、テクスチャの生成と削除の管理はできた。
次はテクスチャのバインドの管理かな。
テクスチャ管理と関係を持たせたいところではあるのだが、なかなか難しそうな気がする。
バインドというのは資源でなく状態だし、どちらかと言えばfg::GLTexturesよりfg::GLCurrentContextに近くなる気がするな。
しかし、fg::GLCurrentContextはスレッドに紐付くが、バインドの状態はfg::GLContextに紐付く。
多少めんどそうな気がするが、イメージはできたかもしれない。
OpenGL、つらい。
*
いや、実際には実装のmesaがつらいのかもしれない。
テクスチャの生成と破棄を管理する型を作ろうとしているのだが、テクスチャがきちんと破棄されたか知る方法がないように思える。
glDeleteTextures()が実行されれば破棄されると思うかもしれないが、なぜかOpenGLコンテキストをglXMakeCurrent()でカレントに設定していなくても成功してしまう。
ならばと直後にglGetError()を呼び出しても、得られるのはGL_NO_ERROR。
これは仕様ではテクスチャ数にマイナスを指定した場合にGL_INVALID_VALUEになる、としかないので仕方ないのだろう。
だったら、glDeleteTextures()で破棄したテクスチャ番号をglBindTexture()すれば、無効なテクスチャ番号ならGL_INVALID_VALUEになるはず、と思ったがやはりGL_NO_ERROR。
であればその破棄されたテクスチャ番号に対し、glTexImage2D()でデータを流し込んだり、glTexParameter()でパラメータを設定したりすればさすがにSEGVとか起きるだろう、と思ってもそんなことは起きない。
エラーなど起きなくても設定対象は存在していないのだし、設定したものをglGetTexImage()やglGetTexParameter()で取得すれば設定したものとは違う値が取れるか、とも思ったけど問題なく(?)取れる。
そもそもglGenTextures()しなくてもテクスチャを扱えてしまう。
もはやお手上げである。
さすがにこれがOpenGLの仕様とは思いたくないなぁ。
*
明日、windowsの方でも試してみようと思う。
大体検証できた。
*
eglに関しては、glxと同じようにeglMakeCurrent()でウィンドウに当たる部分をnullにしても正常に動作した。
wglについては作業中にOSが死んだため途中までしか検証できず、wglMakeCurrent()の動作については確認できなかったが、それ以外の部分で発見があった。
wglの場合、OpenGLコンテキストに当たるものを生成する際にウィンドウに当たるものが必要になるのだ。
glxやeglはウィンドウとOpenGLコンテキストの間に直接的な関係性はなく、glXMakeCurrent()やeglMakeCurrent()で結び付けられることによって機能するようになる。
eglについてはきちんと確認したわけではないので、憶測だが。
ともかく、wglにおいてはOpenGLコンテキストを生成するためにはウィンドウが必須であり、他のもので代用してコンテキストを生成し、makeCurrent()で結び付ける、というような処理をしても描画ができなかった。
前々から関数の構成に疑問があったが、やはりウィンドウとOpenGLコンテキストは1対1で考えるべきものなんだろうな。
*
fg::GLContextのメンバに、fg::Windowの参照を持たせる形にするべきか。
それでfg::GLCurrentの生成をfg::GLContextの参照のみで行なうようにすれば、目的のインターフェースにした上で未定義かもしれない動作をさせることもしなくて済む。
fg::GLCurrentの仕様を考え直すべきかもしれない。
*
疑問に思って試したのだが、描画関係の処理を行なわなければ、glXMakeCurrent()の引数XWindowにNoneを設定しても問題なく動くことを確認した。
が、これは仕様で定義されている動作なのかどうか怪しいところだ。
とはいえ、同じ動きがwglMakeCurrent()やその他でも可能なら、自分で生成するfg::GLCurrentの引数からはfg::Windowの参照を外してもいいかもしれない。
そのように仕様を変えられれば、今考えているOpenGLに関係した機能の実現がやりやすくなるのだ。
というわけで、画像の扱いの前に、その辺をどうにかしてみようかと思う。
明日はwindowsでOpenGL描画処理を書いて、wglMakeCurrent()について検証してみるかな。
いや、OpenGLES用のeglとかいうのもあるのか。
こっちはlinuxでできるし、こっちを先にやるか。
OpenGL3の機能を試す前に、メインウィンドウへのアクセス方法を修正した。
*
今まではfg::Windowの参照を取得するfg::getWindow()という関数だけがあり、メインウィンドウへの再描画要求はそれで取得した参照に対して行なっていた。
しかし、その仕様ではメインウィンドウに対応したfg::GLContextにはアクセスできず、描画タイミング以外でfg::GLCurrentを生成できない。
それにより、メインウィンドウに対するOpenGL関数の呼び出しが描画時以外にできなくて不便だった。
初回だけ行なうような処理を書くのが面倒なので、JPEG画像の描画テストでは描画時にglEnable()の呼び出しやテクスチャの生成など、最初に1回だけ処理すればいいようなことも毎回処理しているのが気にかかっていた。
*
単にどこでもfg::GLCurrentを生成できるようにするなら、fg::getWindow()みたくfg::GLContextの参照を取得するような関数を用意すればいいが、それはあまりに安直だ。
現在の実装では、fg::GLContextの参照に対しては何もできない。
fg::GLCurrentを生成するための引数に使うことしかできないのだ。
だったら、fg::GLCurrentを直接生成した方が早い。
ということで、fg::BasesystemContextの参照を引数に、メインウィンドウに対応したfg::GLCurrentを生成する関数、fg::newGLCurrentForMainWindow()を用意した。
それに合わせて、fg::BasesystemContextの参照を引数に、メインウィンドウに対して再描画要求を行なう関数、fg::repaintMainWindow()も用意した。
*
逆に、fg::getWindow()は削除した。
現時点でもメインウィンドウに対する再描画を行なうためにしか使えないし、そのために参照にアクセスするのはオーバースペックというものだ。
参照にアクセスできてしまうと仮に今後、fg::Windowの参照に対してできることが増えた場合、その全ての機能がメインウィンドウにも使えるようになってしまう。
メインウィンドウに対しては、使える機能を制限したいと前から考えていたので、ちょうどいい感じに仕上げられたと言える。
candymakerはモジュールが多かったので、他のも合わせて1日はちょっときつかった。
*
それでもcandymakerもfgも、sucroseもcmsnakeも全て書き換えることができたし、仮にまだ書き換えてないものがあってもそれほど苦労せずに書き換えられるだろう。
というわけで次に進む。
画像の対応かな。
どう対応するべきか。
取り込んだ画像を特定の扱いやすいフォーマットにするのはいいが、画像取り込み部分はどうしよう。
fgにはインターフェースを用意せず、fgが用意するのは取り込んだ後についてのみにするか。
テクスチャの扱いはOpenGL3から変わっているらしい話も聞くので、その辺試すのも必要かな。
ゴールデンウィークはゆったりしてた。
*
さて、tafはひとまず完成。
fgとsucroseはtafを利用した形にビルドルールを書き直した。
結果、非常にコンパクトになって見やすくなったと思う。
しかしながら、pythonの仕様上間違った書き方しているのに見かけ上はビルドが通っているが、実際には失敗している、というような現象が起きやすくなったかもしれない。
*
candymakerやその他のプロジェクトも明日中には書き換えて、次に進もう。
記述方式についてはいい感じになった。
*
あとは、既存と同様に実装していこう。
機能改良もしたいところだが、具体的にどう変えるかが決まっていない以上どうしようもない。
というか、これ以上は時間がもったいない。
今週中に作り切って、来週前半には既存プロジェクトのビルドルールを一新したい。
ちくしょう厄介だなぁ。
*
コンセプト上、モジュールに配置した変数に直接代入するような記述ばかりになるのだが、記述方法と参照の仕方のバランスを取るのが難しい。
同じ名前で参照しているはずなのに、代入前の値が取れてしまったりする場合があるのだ。
色々と調べていて、おそらく変数に対応するアドレスを決定するタイミングが問題なんだろうな、というのは把握できた。
明日には、納得のいく記述形式にできそう。
根幹は仕上がったように思う。
*
しかしながら、既存のものとは構成が大きく異なるために、これでいいのかどうか不安が残っている。
まぁ、今のところは想定からずれてもいないし、このままC++用のツールも作っていこう。
fgbuilder(仮称)はtafという名前に決定。
*
先週からwscriptの書き方を見直し、どのようにまとめるかを考えていた。
今まで無駄にロジック組んでたところが、実はもっと単純に書けることを知って驚いたりなどしていた。
色々考えた結果、tafのモジュールをインポートし、変数に必要なデータをセットだけで、ビルドルールになるようなものを作ってみようと思う。
*
本当にその通りにできるのか、怪しいところではあるが。
JPEG画像を読み込んで表示するテストプログラム、案外簡単にできた。
*
というわけで、ビルドライブラリの方に取りかかろう。
fgbuilderとかそんな感じの名前で作ってみるかな。
今日から画像読み込みテストを作り始めている。
*
ビルドルールの件については、ビルドライブラリのロード方法をどうしようか考え中。
PYTHONPATHの指定か、importlibの使用か。
前者の場合、exportとかあまり使いたくないので、waf実行時常にPYTHONPATH=と付ける必要があってびみょう。
後者の場合、configure時にだけビルドライブラリのパスを指定すればよいのはいいが、各プロジェクトのビルドルールが多少複雑になってしまう気がする。
どっちもどっちだなぁ。
もうちょい。
*
完全に新しい処理の追加はもう必要ないはず。
既存の処理に似たものを追加して、おそらく問題なく通るであろう自動テストを追加し、動作を確認すれば完了か。
おおむね想定通りに進んでいるが、問題も少し。
*
fg::EventProcsStackの方は大体できた。
記述がいい加減な感は否めないが、処理の流れ自体は間違っていないはずだ。
あとは、不要になる古い機能を除去してしまえば問題ない。
問題はfg::BasesystemEventProcsStackの方だ。
やっつけで無理して実装したツケが、ここに来て回ってきた。
テクニカルな処理をやめ、潔く無難な処理に変更するべきかもしれない。
しかし、そのためにはfgに存在しないインターフェースを新設しなければならない。
そのような事をすると、sucroseのfg::BasesystemEventProcsStackがsucroseのfg::EventProcsStackを使わなければ動作しなくなるので、あまりやりたくはないのだが。
少しぼんやりしてしまった。
*
イベント処理周りを見直していたが、今のままではよくないかもしれない。
何がよくないかと言えば、イベント関数群をpush/popした時に呼ぶ関数の呼び出しタイミングだ。
*
イベント関数群を切り替えることで、ウィンドウ描画時やコントローラ操作時などで呼び出される関数を一度に変更できるようにし、それで画面遷移を表現できるようにしている。
そして、切り替えるタイミングで呼び出すイベント関数も設定できるようにしていて、切り替えた後で使用するデータの生成や、切り替え終わった後に不要になるデータの破棄などをできるようにしている。
しかし、イベント関数群を切り替えた時点ですでに切り替え後のデータが必要になるにも関わらず、現状では切り替え→イベント関数呼び出し、の順になってしまっている。
切り替え前に切り替え時のイベント関数を呼び出さなければ、切り替え後に必要となるデータの準備などできない。
その辺、修正する必要があるな。
そもそも切り替え時に呼び出すイベント関数の構成も少し思うところがあるし、それと合わせて修正しよう。
*
画像読み込み処理を試してみたいところだが、新しいプロジェクトというか、リポジトリを作るのがめんどくさい。
何が悪いのかは大体分かっている。
ビルドツールにwafを使っているが、ビルドルールを書きやすくするために自分で作ったファイルをいちいちコピーしているのが気にかかっているのだ。
できることなら、それ自体を1つのライブラリにまとめてしまいたい。
イベント処理周りの修正を終えたら、画像読み込み/表示をするプログラムを作る前にその辺りをどうにかしてみよう。
sucroseのv0.33.0完成。
*
不要になった処理をばっさりカットしてすっきりした。
へびゲームに、fgの仕様変更を適用して、きちんと動作することも確認済み。
そして、fg::GameDataからfg::BasesystemContextの参照を排除できた。
明日には、コントローラ設定についても対応してみよう。
ここまで来ると、いよいよ画像ファイルの読み込みとかもどうにかしないと見た目がよくない気がする。
ウィンドウと、そのイベント処理を別々の型でやるようにしたバージョンを作った。
*
来週の頭に、fg::BasesystemContext内のfg::Windowをこっちに置き換えてみよう。
いや、他の古い方を使っている部分を新しい方に置き換える方が先か。
ともかく、新しい方を用いる処理の追加、古い方の削除、スレッド周りの古い処理の削除、と問題が出なければそんな感じの流れか?
その辺が全部済んだらバージョンを確定させよう。
一応、完成はした。
*
しかし現状、これを既存のものと置き換えることは不可能だ。
これは新たに作ったものが悪いのではなく、既存の構成の仕様がよくないことが影響している。
というか既存の構成、ゲーム側でOpenGLを使って描画するウィンドウ作れないじゃないか。
この問題を解決するには、ウィンドウの生成とイベント処理の開始タイミングをずらす必要がある。
そうしなければ、ウィンドウを生成し、イベント処理を開始するまでの間にOpenGLの準備をすることができない。
*
次のバージョンで追加して、置き換えられるようにしよう。
あともうちょい、だと思う。
*
ミューテックスと実行中のタスクデータをスレッド処理側のみに置く構成への変更は、これまで書いた処理の配置変更とそんなに多くない処理の追加でスレッド処理側はできた、はず。
残るはタスク管理側だが、こちらについてはほぼもしくは全て、スレッド処理側の関数を呼び出すのみのラッパーのような構成になるので、すぐ済むと思う。
タスク関数内からの、実行中のタスクの再起動処理も、タスク管理側の関数を呼び出すだけだし簡単だ。
明日中には完成すると思う。
別の問題が浮上しなければ。
うまくいかない。
*
もっと構成を単純にすれば、うまくいくかも。
しかし、それをするにはかなり大掛かりな変更が必要になる。
というより、1から作った方が早いかもしれない。
今週中にはどうにかしたいところ。
一応は完成、だがバグがある。
*
キャンセル周りが不完全だ。
キャンセル時にスレッドの再起動処理もしている関係か、デッドロックを起こしているようだ。
明日中に解決したい。
スレッド周りの改修はほとんどできた。
*
21日の分はちょっと勘違いしていた。
スレッド処理側はより単純になるはずだったのだ。
それで、結果的に既存のものよりコンパクトになった。
その代わり、起動管理側は既存のものより規模が大きくなった。
*
後は、実行中のタスクの再実行と、起動管理部分のリファクタリングくらいか。
来週の頭には仕上げたい。
スレッド周りの改修を進めている。
*
とりあえず、スレッド処理側の処理はほぼできた。
とはいえ、ここまでは既存の処理をちょっと変えただけだから、比較的簡単にできた。
ここから先は、新しい構成を構築する必要がある。
なかなか骨が折れそうだ。
とりあえず、へびゲームとコントローラ設定について対応した。
*
書き換え程度ではあまり実感できなかったような感触だが、それでも従来よりましになったな、という気はする。
fg::GameData内にfg::BasesystemContextの参照を含めなくてよさそうな感じになったのは大きい。
とはいえ、含めなくてよい、ではなくよさそう、であり、他の部分にも修正を行なわないとまだ含めなくてはいけない状況にもなる。
具体的に言えばスレッド周りだ。
やはり、早いところ修正が必要だな。
fg::EventProcsViewer追加完了。
*
実際にはfg::EventProcsStackを見ているし、fg::EventProcsStackViewerの方が合ってるかなとも思ったが、冗長な気がしたのでこれでいいことにした。
これでイベント周りの修正は完了した。
来週の頭に、過去に作ったプログラムに修正を適用して使い勝手を確認してみよう。
fg::Event追加完了。
*
次はfg::EventProcsStackViewer、と仮称しているものの追加だ。
*
現在の仕様では、fg::EventProcsCallerを生成するためにはfg::EventProcsStackの参照が必要だ。
fg::BasesystemEventProcsStackに設定している関数を呼び出すために、fg::BasesystemContextからfg::BasesystemEventProcsStack内にある、fg::EventProcsStackの参照を取得できる。
そこまではいいのだが、fg::EventProcsStack自体を参照すると、fg::EventProcsManagerを介してfg::EventProcsをプッシュしたりポップしたり、という操作も可能になってしまう。
fg::BasesystemEventProcsStackは、fg::BasesystemEventProcsをプッシュ、あるいはポップするためのものであり、それより機能が少ないfg::EventProcsをプッシュしたりすると、予期しない動作になるのは目に見えている。
*
そこで、プッシュ/ポップはfg::EventProcsManagerを介して行ない、関数の呼び出しはfg::EventProcsStackViewerを介して行なう、という風に分けようと考えている。
fg::EventProcsStackViewerはfg::EventProcsStackから取得できるようにする。
fg::BasesystemContextから取得できるのも、fg::EventProcsStackViewerの参照にすれば、関数の呼び出しは可能なままで、fg::BasesystemEventProcsStackに対するfg::EventProcsのプッシュ/ポップは不可能にできる。
*
それを完了しても、既知の問題はもう1つある。
が、そっちは今の仕様では解決が難しい気がする。
特定状況下でfg::EventProcsCallerを生成するとデッドロックがかかってしまう、という問題だ。
もっと言うなら、fg::BasesystemEventProcsStackのプッシュイベント関数内で、といったところか。
詳しく確認はしていないのだが、fg::EventProcsCallerの生成時にはfg::BasesystemEventProcsStackのスレッド処理を待機する処理が入っているため、おそらくその関係だと思う。
fg::Eventを追加した時に、fg::Eventからfg::EventProcsCallerの参照を取得できるようにしたため、それを利用することで回避はできるのだが、問題のタイミングでfg::EventProcsCallerが生成可能なことは変わっていない。
できることなら、問題の起きる記述はできないようにしたいところなのだが。
またしても想像よりも時間がかかりそうだ。
*
fg::Eventを追加するに当たり、既存部分への変更も多く必要になっている。
とはいえ、明日丸1日がんばればどうにかなるかもしれないが。
遅くとも今週中には片付けてしまいたい。
*
まぁ、実現は可能そうだし、ユーザーデータを持たないイベント関数内でユーザーデータにアクセスしようとするような記述は、コンパイル段階で弾かれるなど、想定よりももっと便利になりそうだし、いい感じだ。
想像よりずっと時間がかかってしまった。
*
既存のものを維持したまま、それを差し替えるものを追加するのはやはり手間がかかってよくない。
できる限り、そういうことをしないで済ませたいものだ。
*
そんなわけで、fg::EventPropertiesをfg::EventProcsという型に差し替えた。
一区切りついたので0.29.0としたが、まだ終わりではない。
0.29.0は差し替えのみで、ここからより使いやすくするために追加を行なっていく。
*
手始めに、と言っても今のところ予定している追加は2つだが、統合されたイベント型を追加する。
現状の仕様ではイベント型は完全に別々であり、イベント型共通の機能というのを用意したくても、各イベント型に関数を追加する、という方法でしか実現できない。
そこで、fg::Eventというテンプレート型を用意する。
各イベント型へのアクセスや、イベント型共通の機能の使用はfg::Eventから行なう形にする。
この形式に変更することで、記述が簡略になる部分もあるはずだ。
物は試し、と画像ファイルを読み込み、表示するだけのモジュールを作ろうとしていた。
*
しかし、どうにもfg::EventPropertiesが使いづらく、どうにかならないかと考えていたら、改訂案を思い付いてしまった。
イベント関数と、イベント関数で利用するデータを別々にして考えているからいけないのだ。
2つを合わせて考えれば、いい感じにできそう。
タスク周りのと違って、こちらはインターフェースも大きく変わるし、変える前のものは使い物にならないと言える。
こっちは画像ファイル読み込みの前に片付けてしまおう。
タスク周りの改訂案を思い付いてしまった。
*
考え方は変わらないけど、構成はかなり大きく変わるしすぐにはやりたくないな。
しかし、今の構成より無駄が減りそうなので、そのうちやりたい。
暫定的な基本コントローラ設定画面を作れた。
*
コントローラのボタン入力により、基本メニューボタン、スタートボタン、セレクトボタンの割り当てをファイルに出力できるようになった。
画面、といっても描画処理がまだついてないけど。
現時点では画像ファイルを読み込む機能などもないので、きちんとした画面描画をするのは難しい。
他にも色々問題はあるが。
*
で、この後は実際にゲームで使うコントローラ設定画面を、と行きたいところだがそれは難しいだろうな。
なんせ、まだどのような仕様にするか固まってない。
なので別のところ、例えば前述の画像ファイルの扱いなどを進めようかと。
今まであまり積極的にやった記憶がないが、避けては通れないしいい機会だろう。