2013年04月01日

クラウドファンディングへ応募してみる

吉里吉里2 VC ビルド対応をクラウドファンディングのCAMPFIREへ応募してみた。
7営業日以内を目安に可否判定されるらしい。
4/10 までに掲載可能になるか否かがわかる感じか。

「C++ Builder でのみビルド出来る吉里吉里2 を Visual C++ でもビルド可能にし、吉里吉里2と同一ライセンスでオープンソースとしてソースコードを公開する」と言うものなんだけど、リターンがソースコードを公開すると言う辺りが少し微妙かな。
パトロンだけに何かリターンがあるわけじゃないので、その辺り懸念点ではある。
掲載された後も金額が集まるのかどうか気がかりだけど、それ以前に掲載されるかどうかの時点で厳しい気もしている。
何にしてもやってみないことには始まらないので応募した。
どうなることかな。

投稿者 Takenori : 23:59 | トラックバック

2013年04月03日

CAMPFIRE には掲載されず

クラウドファンディングへ応募してみる で書いたようにCAMPFIREへ応募したものは掲載見送りの連絡があった。
途中質問メールがあったのでもしかしたらいけるのかな?とも思ったけどダメだった。
特に理由等書かれていなかったので、今後の参考のためにも差し支えなければ理由(問題点や懸念点)を教えてくださいと返事した。
何がダメなのかわからないと対応のしようがないし、今後全没なのかよく分からない基準でうまくいったりするのか判断できない。

CAMPFIREがダメだったということで、次にREADYFOR へ応募した。
ここもダメとなると本件では国内のクラウドファンディングは使えないと判断するしかないかな。

投稿者 Takenori : 16:01 | トラックバック

2013年04月08日

吉里吉里2 VCビルド対応検討項目

C++ Builder でのみビルド出来る吉里吉里2 を Visual C++ でもビルド可能にする。
また、レガシー機能は削除して、モダンな機能取り込みも考慮する。

吉里吉里2 は C++ Builder 5 ~ 2007 でビルド可能ではあるが、この制限が保守性において懸念材料となっている。
オフィシャルビルドは C++ Builder 5 で行われているが、現在 C++ Builder 5 は入手できない。
この問題を解消するべく Visual C++ でもビルド可能にする。

保守性等のため完全互換ではなく、いくつかの機能の削除と VCL からの変更による挙動の変更が考えられるが、ゲーム実行等実使用において問題がない動作を目指す。
検討している内容を適用すると KAG3 はそのままでは動かない変更が入る。

Windows8 で顕在化してきている問題として以下の物がある。
・IME切り替え周りで VCL が使用している旧APIで問題があり、バイナリ書換えにより対処している。
・DirectX 7 の問題か、クリッピングがおかしくゴミが残る(C++BuilderでもDirectX 9等への対応は可能と思われる)。

これ以外にもいろいろと苦しくなってきている部分はある。


以下、変更検討事項。
問題等が予想される場合は、コメント等でご指摘いただければ再考する。
また、開発中に顕在化した問題によって他に変更が入る可能性もある。

予定している変更項目。
・VCL を排除。
・コンソールやコントローラー等のデバッグ機能の切り離し。
・DirectX 7 の描画は DirectX 9 へ変更。
・MIDI / CDDA / Pad クラスは削除。
・KAGParserクラスの本体からの削除。
・libjpg をSIMD版へ変更し高速化。
・zlib/libpng を最新版へ。
・エンジン設定用のオプションファイルはexeから分離、もしくはリソースへの移動。
・正規表現エンジンを鬼車へ変更。
・ERIフォーマットの非サポート。
・コンパイル時のワーニングを全てなくす。
・メニュー機能(Menuクラス)の削除デバッグオプションもしくはプラグインへ。
・その他 Windows/Layer クラスでいくつかのメソッドの削除。


・VCL を排除。
C++ Builder 以外でコンパイル出来るように VCL は排除する。

・コンソールやコントローラー等のデバッグ機能の切り離し。
コンソール機能はデバッガ側頼りにする。
ログファイルは残す。
コンソールやコントローラーのデバッグ機能はリリース時はない方が好ましい。

・DirectX 7 の描画は DirectX 9 へ変更。
Windows8 でクリッピング問題が出ているようなので、DirectX 9 へ変更する。
解決するかどうかは不明。

・MIDI / CDDA / Pad クラスは削除。
レガシーな機能と思われる。

・KAGParser は本体から分離。
現在はクラスプラグインが実現できるようになっているので、プラグインとした方が良い。
メンテナンスがきわめて困難なソースコードとなっているので、個人的には完全互換ではない別物にした方が良いと思っている。

・libjpg をSIMD版へ変更し高速化。
・zlib/libpng を最新版へ。
現状に合わせて置き換え

・エンジン設定用のオプションファイルはexeから分離、もしくはリソースへの移動。
ややトリッキーな方法なので削除。

・正規表現エンジンを鬼車へ変更。
boost の特定バージョンに依存した正規表現エンジンになっているが、移植性を上げるため鬼車へ変更する。

・ERIフォーマットの非サポート。
要らないと思われる。

・コンパイル時のワーニングを全てなくす。
エラーを探すのが辛いので、ワーニングは全てなくす。

・メニュー機能(Menuクラス)の削除デバッグオプションもしくはプラグインへ。
Windows 8 タブレットでフルスクリーン時にタッチだとメニュー出せないため、あっても使えない。
他の操作で出来るように組み込むべき。
ツール用途ではないと厳しいという意見を踏まえ、標準ではOFF 、デバッグオプションもしくはプラグインで ON 可能と言う形へ。

・その他 Windows/Layer クラスでいくつかのメソッドの削除。
Windows クラスのタブレット化において、問題となりそうな機能やゲームとして不要と思われる機能の削除。
ただ、互換性も考慮して取捨選択する。
Layer クラスで互換性のために置いているとドキュメントに記載されているメソッドの削除。


変更によって影響が出る可能性がある項目
VCL では、不可視のメインウィンドウを内部で作り、メッセージ等の処理をそこである程度行う様な構造になっているが、VC で作る場合、最初に生成されたウィンドウをメインウィンドウとして扱う一般的な方法にすると思われるので、細かい部分での挙動が変わる可能性がある。
krflash は非サポートとなる可能性がある。


工数の関係から状況次第で対応検討項目。
・マルチタッチ対応。
・フリック等ジェスチャー系の入力。
・ペン入力。
・画面の向き対応。
・Ogg Vorbis を高速化プロジェクトのものへ置き換え。
・アセンブリコードをイントリンシックで書き換え、SSE2 のサポート。
・64bit対応(イントリンシック書き換え必須、ポインタサイズ考慮必要)。

投稿者 Takenori : 20:35 | コメント (4) | トラックバック

吉里吉里2 VCビルド対応ファンディング調査

吉里吉里2 VCビルド対応検討項目 を実現するためにお金集めようと言うエントリー。

見積金額 200万円。

上述のエントリー内容を実装し、動作確認が出来た段階で吉里吉里2と同じライセンスで公開。
みんなで叩いてバグを減らす。
工数の関係から状況次第で対応検討項目は集まった金額次第で考慮。

1万円単位で○万円出してもいいと言う人がいれば、メールを下さい。
人数分契約書を作って、開発するという方式を考えています。
1万円単位と書いたのは、事務手続きの関係からです。
何千枚も契約書作るのは現実的ではないので。

契約書を作る関係で、住所と名前が必要なのでそれを私に明かしても良いという人限定です。
また、ドキュメント等のコントリビューター項に載せる名前は別の方が良い方は、その名前。
コントリビューター項に載せないで欲しい場合は、その旨記載してください。

メールには以下の内容を書いてください。
・住所と名前
・金額
・コントリビューター項に載せる名前
・支払い時期
契約書ひな型で問題ないか否か
・紙の契約書が必要かどうか

メールアドレスはここに書いています。

一応自分は1人月分くらいは負担する心づもり。
他に1人月分くらいは出す、20万出すという話あり。

以下、宣言してくれた人のつぶやき貼り付け。
twitter で jin1016 宛 へ宣言リプライもらえたら追加します。

togetter まとめ

投稿者 Takenori : 20:40 | トラックバック

2013年04月09日

メニューについて補足

ウィンドウの標準的なメニューはレガシー な機能か?と言と、現時点ではそうでないとしても片足突っ込んでいる状態と思う。
なくす、なくさないを考えると、その境界線上にある機能。
今はまだ互換性のためにあった方が助かる機能だけど、将来的には削ってしまいたいものだろう。

フルスクリーンの場合にタッチで操作できないと言うのは、現状ある直接的な問題だが、タブレットやスマートフォンへの移行を考えると代替手段の準備はほぼ必須になるのは間違いない。
また、移植性を考慮したデザインへの移行を促したいとも思う。

反対意見が出るのは承知で書いた。
それでも時計の針を進めたかったと言うこと。

まあ、メニューがあるのならお金出すと言う人がいるのなら、じゃあ標準ではOFF 、デバッグオプションもしくはプラグインで ON 可能と言う形にすると言う話でもあるけども。
プラグインで実現可能なら、その形が濃厚かな。

投稿者 Takenori : 01:35 | トラックバック

吉里吉里2 VCビルド対応 諸条件

吉里吉里2 VCビルド対応ファンディング調査で記載しておらず、聞かれたことなどを書きます。

VC は、最新版である Visual Studio 2012 (C++) Pro で対応する。
OS は VS2012 の制約により、XP 以上となる。
スケジュール は以下の通り。
最終期限は、今年いっぱい(2013年12月末)まで (契約書上の期限)。
予定スケジュール
実装期間 : 4月~6月
テスト期間 : 7月、8月
支払いは前払いが好ましいが、後払いでも可。
後払いの場合、完了月の翌月末まで。
予定通り進めば9月末まで。
テストは規模的に一人で全て網羅は無理なので、実装完了後公開しみんなに叩いてもらうことを想定しています。
もちろんテストは順次進めますが、安定性向上のためには多くの方の協力が必要になります。

名前と住所についてですが、公開されるのは私個人のみにです。
公に公開されるのは、「コントリビューター項に載せる名前」でなしでも問題ありません。

契約書
後ほどひな型を公開します。
形式的に受託開発となります(寄付(贈与)ではありません)。
内容が関連する方は確定申告にて経費として申告可能と思われます。

投稿者 Takenori : 16:11 | トラックバック

吉里吉里2 VCビルド対応ファンディング途中経過

一晩経った現在の状況です。

提供者金額(万円)
deeさん 20
casperさん 5
(有)MCFさん 10
sakanoさん 3
青猫さん 5
nagaiさん 10
Ruwさん 5
giwさん 3
ゆんさん 5
永劫さん 3
りょうごさん 5
AZ-UMEさん 3
京 秋人さん 6
Katsumasa Tsuneyoshiさん(メールにて) 3
ぢゃくそんさん 1
miahmieさん(コメント欄にて) 5
サークル獏さん(メールにて) 3
アザナシさん 2
はっしぃさん(メールにて) 5
靄間 一郎さん 2
わっふるさん(メールにて) 2
M2さん 50
ワムソフトさん 50
ノーツさん(メールにて) 50
自分 50
合計 306

投稿者 Takenori : 16:14 | トラックバック

吉里吉里2 VCビルド対応契約書ひな型

支払い条件については、前払い、分割払い、後払い等要求条件によって、変更可能です。
出来れば前払い(4月末日)にしていただけると助かります。
支払い月は後払い期限(9月末日)までの間で変更可能です。
その他修正した方が良い項目がある場合は、個別、もしくはコメントでお願いします。
この契約書ひな型はたたき台です。
特に問題ない場合は、このまま印刷して送付します。

2013/04/10
第5条に「修正BSDライセンス」に関係する記述を追加
ただし、乙は、その成果物を最終的に「吉里吉里ライセンス」および「GPL」のデュアルライセンス、もしくはW.Dee氏指定のライセンスを加えたトラプルライセンスで、甲および「吉里吉里プロジェクト」及びそれを利用する第三者に対して提供するものとします。
W.Dee氏指定のライセンスが修正BSDライセンスの場合、修正BSDライセンスで甲および「吉里吉里プロジェクト」及びそれを利用する第三者に対して提供するものとします。

2013/04/11
最後の方で
修正前「本契約の成立を証するため、本覚書二通を作成し、」
修正後「本契約の成立を証するため、本契約書二通を作成し、」
他に
修正前「トラプルライセンス」
修正後「トリプルライセンス」
の2点を修正。
------

ソフトウェア開発業務委託契約書

貴方の名前(以下「甲」という)と私の名前(以下「乙」という)は、次の通り業務の委託をするにあたり、次の通り合意し、契約(以下「本契約」という)を締結する。

第1条(本件ソフトウェア)
本件により乙が開発するソフトウェアは以下のとおりとする。
「吉里吉里2 VCビルド対応」

第2条(業務の範囲)
本件業務の内容は、以下の通りとする。
1.業務概要
吉里吉里2 を Visual Studio 2012(C++) Professional でビルド可能にする

2.業務詳細
・吉里吉里2 を Visual Studio 2012(C++) Professional でビルド可能にする。
・MIDI / CDDA / Pad クラスは削除する。
・その他詳細仕様及び設計詳細は乙に一任する。

3.スケジュール及び納品
・作業スケジュール
自 2013年4月10日 至 2013年12月31日

・納品
吉里吉里2と同一ライセンスでソースコード及び実行バイナリコードを一般に公開し2カ月間のテスト期間経過後納品完了とする。
その後、W.Dee氏の了承のもと吉里吉里プロジェクトに対してコードを規定のライセンスで寄贈する。
納品は上記スケジュールより前倒しでも可能とする。

第3条(対価及び支払条件)
1. 甲は乙に対して本業務の対価として金\○○円也(消費税込)を以下の通りに支払う。
2. 甲は、本業務の対価を、4月末日までに乙の指定する銀行口座に振り込むことにより乙に支払う。
( 2. 甲は、本業務の対価を、納品完了後末締めで翌月末日までに乙の指定する銀行口座に振り込むことにより乙に支払う。)

第4条(瑕疵担保責任について)
本契約に基づき作成されたプログラム等に瑕疵があった場合、乙は、公開後2カ月間のテスト期間のみ修正を受け付け、その後の修正は任意の対応とする。

第5条(著作権並びに著作人格権について)
本契約に基づき乙が作成し提供するプログラム等の権利(著作権法第21条から第28条に定めるすべての権利を含みます)はそのまま乙に属するものとします。ただし、乙は、その成果物を最終的に「吉里吉里ライセンス」および「GPL」のデュアルライセンス、もしくはW.Dee氏指定のライセンスを加えたトラプルライセンスで、甲および「吉里吉里プロジェクト」及びそれを利用する第三者に対して提供するものとします。
W.Dee氏指定のライセンスが修正BSDライセンスの場合、修正BSDライセンスで甲および「吉里吉里プロジェクト」及びそれを利用する第三者に対して提供するものとします。

第6条(協議)
本契約締結後に記載内容に変更が生じた場合は、甲、乙協議の上、書面により別に定めるものとします。
本契約に定めのない事項又は本契約の内容等に疑義が生じた場合には、その都度、甲、乙双方が民法をはじめとする法令等を踏まえ、誠意をもって協議します。


本契約の成立を証するため、本覚書二通を作成し、甲乙記名捺印の上、各自一通を所持する

平成○○年○○月○○日

甲: 貴方の住所と名前
乙: 私の住所と名前

------

投稿者 Takenori : 20:32 | トラックバック

2013年04月11日

吉里吉里2VC対応追加項目希望アンケート

金額が見積もりより多くなっているので、追加で何が欲しいかコメントください。
以下に、検討項目に上げていたものなどを列挙するので、この中からこれが欲しいというのがあればそのコメントも下さい。
コメントはツイッターやメールでもかまいません。

検討していた項目の内、入れるのがほぼ確定しているもの
・マルチタッチ対応。


工数の関係から状況次第で対応検討項目。
・フリック等ジェスチャー系の入力補助。
・ペン入力。
・画面の向き対応。
・Ogg Vorbis を高速化プロジェクトのものへ置き換え。
・アセンブリコードをイントリンシックで書き換え、SSE2 のサポート(工数大)。
・64bit対応(イントリンシック書き換え必須、ポインタサイズ考慮必要)。


追加で上げられているものや思い付くもの
・Layer クラスから Image クラスを分離可能にする。
・KAG3 では対応しなくなるので、ポストKAGを作る。
・Layer.operateAffineで引数mode指定時の未実装機能。
・Octet の未実装メソッド追加
・KAGParser に近い機能を持ち再実装したもの。
・TJS2 のコンパイル部分の整理。
・マルチプラットフォーム化。


・Layer クラスから Image クラスを分離可能にする。
ツール作るときなどに色々と苦労するようなので。

・KAG3 では対応しなくなるので、ポストKAGを作る。
KAG3 に相当するものがないと困る人が多いと予想されるため。

・Layer.operateAffineで引数mode指定時の未実装機能。
あった方が便利。

・Octet の未実装メソッド追加
あった方が便利。

・KAGParser に近い機能を持ち再実装したもの。
現状のKAGParserのソースコードは保守性が低いので、だいたい同等機能のものを作った方が保守性が上がる。

・TJS2 のコンパイル部分の整理。
少し見通しが悪いので。

・マルチプラットフォーム化。
よくある要望。
現在の win32 フォルダ内のソースコードは厚いので、もっと薄いプラットフォーム互換維持層を作り、その API をコールすることで移植性を高める構造へ持っていく予定ですが、マルチプラットフォーム化までは工数的に無理と思われます。


-----
追加
・Layerクラスは画像処理系とイベント処理系を完全に分離して,TJSスクリプト側で互換を取る。
TJS2 に foreach を組み込む。
ScriptsExプラグインの Scripts.clone() を本体に組み込む。
オブジェクト内のメンバ存在チェックメソッド を本体に組み込む。
TJS2 で型指定も可能にする。
TJS2 に JIT を導入して高速化する。
TJS2 に型推測を入れて高速化する。
TJS2 にコルーチンが欲しい。
TJS2 にrubyのブロックみたいなのが欲しい。
TJS2 にパッケージ機構が欲しい。
シリアライズ機能が欲しい。

投稿者 Takenori : 17:32 | コメント (2) | トラックバック

2013年04月12日

吉里吉里2 VCビルド対応の流れ

吉里吉里2 VC ビルド対応を実現するため、クラウドファンディングサイトの CAMPFIRE に応募してみるも断られる。
続いて READYFOR にも応募してみるも断られる。

対応検討項目 を上げた後、独自でファンディングを行うべく ファンディング調査 を公開し、お金を出してくれる人を募る。
質問等を受けて 諸条件 を公開。
( メニューの扱いについて補足説明追加 )

ファンディング途中経過 を報告。
契約書ひな型 を公開。
メールをもらった方と順次契約等手続きを行う。

当初見積もりよりも多く集まったので 追加項目希望アンケート を実施中。

吉里吉里2 VC ビルド対応って結局何?
主目的は……
・保守性の改善による開発効率のアップとソフトウェア寿命の長期化。
・コンパイラ入手性改善による開発者増加と発展。

その他にマルチタッチ対応などによるタブレット端末最適化に向けた下回り整備も行います。
また、副次的効果として個別バイナリを作りやすくなることからクラッキング対策の強化が行いやすくなります。

投稿者 Takenori : 13:52 | トラックバック

2013年04月14日

開発メモ その1

Visual C++ への書き換えで生じた問題等を メモしていく。

呼び出し規約付き関数ポインタは、
int (__stdcall *funcp)(int);
このように書かないといけない。
以下のようにするとエラー。
int __stdcall (*funcp)(int);

const ポインタの参照渡しは、呼び出し側で非constポインタを渡すとエラー
int func( const int *&p );
このような関数に
int* buf = a;
func( buf );
とするとエラーになる。
const int* buf = a;
func( buf );
このように書く。

ObjectList 関係で、tObjectList の ObjT * & operator [] (tjs_int index) で * から *& に変換できないと言われる。
tVoidObjectList を void* ではなく、テンプレートで型を指定する形に書き換えた。

zlib 1.2.7 の Visual Studio 2010 のプロジェクトファイルを 2012 に変換してスタティックライブラリを作ると、リンク時に関数がないといわれる。
Visual Studio 2012 で新規にプロジェクトを作ってソースコードを入れてビルドすると問題ない。
デバッグオプション等の問題かもしれない。
後で、詳しく見てみる。

吉里吉里2 はフルスクリーン化時 Window 作り直しているが、解像度変更等しないもののみにするとこの辺り不要になるが、プラグイン等でWindowが作り替えられる前提で作られているものもある。
単純に作り替えられたとしてコールしても問題ないか、また作り替えなくても問題が出ないか検証する必要がある。

メニューをプラグイン化した場合、フルスクリーン時はメニューが機能しなくても問題ないだろうか?
ツール用途で残して欲しいのであれば、フルスクリーン時に使えなくても問題はなさそうだが……

C++ Builder では、_argc と _argv でコマンドライン引数を得られるが、Visual C++ の場合 __argc と __argv になる。
ラッピングしたものを使う方が良い。
VCL の ParamStr が使われている箇所もある。

PluginImpl.cpp で #include "GraphicsLoaderImpl.cpp" と cpp が include されている。
GraphicsLoaderImpl.cpp もプロジェクトに含まれているが、C++ Builder では通っている。
Visual C++では以下の3つのヘッダーに書き換えると通るが、疑問が残る。
#include "GraphicsLoaderImpl.h"
#include "MsgImpl.h"
#include "SysInitIntf.h"

bool へのキャスト演算子オーバーロードがうまく機能していない様子
pamra.operator bool(); 等明示的に呼び出してやるとうまくいく。
所々(tjs_int)へキャストしてboolをとっているが、bool へのキャストと tjs_int へのキャストのオーバーロードされたメソッド内部はオブジェクトの変換等で扱いが違う。
オブジェクトは tjs_int へ変換できないが、bool の場合は非NULLかどうかでの判断となっている。
これらは意図した記述なのか、単なる記述の揺れなのかよく読まないとわからない。

投稿者 Takenori : 20:56 | トラックバック

2013年04月16日

吉里吉里2 のアセンブリコード

吉里吉里2 visual/IA32 sound/cpu のアセンブリコードは nasm 2.08.01 が必要。
nasm 2.10.07 だとエラーが出る。

VC 用には nasm -g -f win32 %%d とする。

イントリンシックに書き換えてしまいたいところだが、ちょっとブレンド処理など量が多い。

投稿者 Takenori : 20:22 | トラックバック

2013年04月17日

現在のところの要望まとめ

・マルチタッチ対応。
・フリック等ジェスチャー系の入力補助。
・ペン入力。
・画面の向き対応。
・画面回転ロック
・Ogg Vorbis を高速化プロジェクトのものへ置き換え。
・アセンブリコードをイントリンシックで書き換え、SSE2 のサポート(工数大)。
・64bit対応(イントリンシック書き換え必須、ポインタサイズ考慮必要)。
・Layer クラスから Image クラスを分離可能にする。
・Layer クラスは画像処理系とイベント処理系を完全に分離して,TJS スクリプト側で互換を取る。
・KAG3 では対応しなくなるので、ポストKAGを作る。
・Layer.operateAffine で引数 mode 指定時の未実装機能。
・Octet の未実装メソッド追加
・KAGParser に近い機能を持ち再実装したもの。
・マルチプラットフォーム化。
・ScriptsEx プラグインの Scripts.clone() を本体に組み込む。
・オブジェクト内のメンバ存在チェックメソッド を本体に組み込む。
・TJS2 のコンパイル部分の整理。
・TJS2 に foreach を組み込む。
・TJS2 で型指定も可能にする。
・TJS2 に JIT を導入して高速化する。
・TJS2 に型推測を入れて高速化する。
・TJS2 にコルーチンが欲しい。
・TJS2 に ruby のブロックみたいな機能。
・シリアライズ機能。
・Layer クラス周りを DLL 化して、グラフィック部分を取り替え可能にする。
・Layer 画像を BMP 以外に、PNG / JPG / TLG5/6 でも保存できるようにする。
・αチャンネル付き JPEG もしくは、JNG のサポート。

投稿者 Takenori : 22:35 | トラックバック

2013年04月20日

追加検討機能:コマンドラインなど

コンソールを削る代わりと言うか、ツールとして便利にするためにコマンドラインから起動された場合は、ログをコマンドラインへ出力する機能をつけようと思う。
コマンドラインで実行する場合、そっちの方が便利だろう。

他に現在は startup.tjs から起動するが、任意の TJS2 ファイルを指定して、その TJS2 ファイルを実行可能にするのと、コマンドライン引数で渡された文字列をスクリプトとして実行することも出来るようにする予定。
任意スクリプトはその方がツールやテスト便利だし、引数文字列を実行はワンライナー等使い道がある。
ゲーム用というより、ツールやテストのための機能だけど、利便性が高まるはず。

投稿者 Takenori : 16:42 | トラックバック

追加検討機能:「戻る」「進む」キー、SS

要望まとめのみではなく、思い付いたときに、ブログに書いていく。
実装するかどうかわからないけど。

5ボタンマウスの+2ボタンもついでだから機能追加することを検討。
+2ボタンは、「戻る」や「進む」ボタンにだいたいなっているはず。
何に使うのかは置いといて。
案としては、自分だとバックログが必要になる時の9割以上が1個前のメッセージを読み返したい、読みとばしてしまったので読みたい、と言う用途なので、「戻る」ボタンでメッセージが1個戻ると便利。
そういう機能があるとバックログをあまり使わなくなる。

スクリーンショット用のメソッドやショートカットキーがあるといいかもしれない。
マイピクチャに保存して、そのパスを返すような。
JPEG/PNG 保存とセットになるが。
常時 ON ではなく、デバッグオプションで有効無効があると良さそうだけど。

タブレットで長時間プレイしているとバッテリー残量が気になるときがあるので、バッテリー残量が取得できるといいかもしれない。

投稿者 Takenori : 17:22 | トラックバック

2013年04月22日

SIMD libjpeg で出力ピクセルフォーマットを指定する

IJG JPEG library 高速化版 で出力ピクセルフォーマットを指定することで、読込み後の変換を省く方法。

jmorecfg.h の以下のようになっているところを書き換えることで変更できる。

#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
#define RGB_GREEN 1 /* Offset of Green */
#define RGB_BLUE 2 /* Offset of Blue */
#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */

#undef RGBX_FILLER_0XFF /* fill dummy bytes with 0xFF in RGBX format */


よくある BGRA 32bit フォーマットで、アルファ値を 0xFF で埋めるには以下のように指定する。

#define RGB_RED 2
#define RGB_GREEN 1
#define RGB_BLUE 0
#define RGB_PIXELSIZE 4
#define RGBX_FILLER_0XFF

このようにすることで読込み後に 24bit から 32bit への変換を行わなくても、32bit で画像データで得られる。

投稿者 Takenori : 18:31 | トラックバック

JPEG 読込み速度比較

SIMD libjpeg で出力ピクセルフォーマットを指定する を適用して、直接指定領域へデコードするようにした吉里吉里Z と吉里吉里2 で JPEG 読込み速度比較。
画像サイズは HD サイズと 640x480 を使用。
10枚の JPEG 画像を読み込むのにかかった時間。
6回計測し、最初の1回を除外した 5回の平均。
出力ピクセルフォーマット指定で 24bit にして読込み後に変換した場合も計測。

設定吉里吉里2吉里吉里Z速度比吉里吉里Z 24bit速度比
HDサイズ 整数 AAN + フィルタあり 221.2ms 70ms 3.16倍速 81.4ms 1.16倍速
640x480 整数 AAN + フィルタあり 75.2ms 29.4ms 2.56倍速 34ms 1.16倍速

24bit から 32bit の変換を無くした場合と比較すると 1.16倍くらい速くなる程度。
吉里吉里2 と比較してかなり速くなっているのは何の影響だろうか……
吉里吉里2 も SIMD 版を使っているということだったが、コンパイラの差でここまで大きな差が出るとはちょっと考えづらい。
開発中バージョンのため最終的には結果がまた変わる可能性がある。
キャッシュの影響だと思われるが画像サイズがでかくなるほど速度が上がりそう。


IDCT のアルゴリズム比較。
吉里吉里Z のみで AAN と LLM で比較。フィルタは両方あり

設定吉里吉里Z LLM吉里吉里Z AAN速度比
HDサイズ 83.6ms 70ms 1.19倍速
640x480 32.4ms 29.4ms 1.10倍速

吉里吉里2 では、AAN + フィルタありがデフォルトになっているが、吉里吉里Z は LLM + フィルタありをデフォルトにしてもいいかな。
クオリティーは LLM の方が上で、こちらの方が一般的。

投稿者 Takenori : 23:57 | トラックバック

2013年04月23日

追加検討機能:画像読込みのマルチスレッド化

System.touchImages コール時にバックグラウンドで画像を読み込む機能。
実際には Layer.loadImages でもマルチスレッドで読み込まれることになるが、そちらはオーバーヘッドが大きくなる可能性がある。

ディスク読込みスレッドとデコードスレッドの2つのスレッドで画像ファイルを読み込むようにし、複数ファイル読込み時の並列性を上げて読込み速度の向上を図る。
メインスレッドとは異なるスレッドで読み込まれることになるので、スキップ時等に高速化が期待できる。

投稿者 Takenori : 01:52 | トラックバック

zlib 1.2.7 を VS2012 で使えるようにビルド

ランタイムライブラリをマルチスレッド、スタティックライブラリでリンク、リンク時の最適化ありで Visual Studio 2012 (C++) でリンクできるように zlib 1.2.7 をビルドするには makefile に少し手を加える必要がある。
そのままビルドすると「モジュールは SAFESEH イメージには安全ではありません。」などと出る。

変更するのは win32/Makefile.msc で、アセンブリを使う形でメイクする場合。

CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC)

CFLAGS = -nologo -MT -W3 -O2 -GL -Oy- -Zi -Fd"zlib" $(LOC)

MD を MT に変更して、GL を足す。
デバッグ版は、MTd にする必要がある。


ASFLAGS = -coff -Zi $(LOC)

ASFLAGS = -coff -Zi -safeseh $(LOC)

safeseh を足す。


LDFLAGS = -nologo -debug -incremental:no -opt:ref

LDFLAGS = -nologo -debug -LTCG -incremental:no -opt:ref

LTCG を足す。


ARFLAGS = -nologo

ARFLAGS = -nologo -LTCG

LTCG を足す。

上記修正を加えた後メイクして出来た zlib.lib を使えば問題なくリンクできるようになる。

投稿者 Takenori : 22:17 | トラックバック

2013年04月24日

マウスカーソル画像の仕様変更に関して

吉里吉里Z では以下のカーソル画像が非サポートになります (これ以外にも今後変更になる可能性はあります)。

crDrag
crNoDrop
crHSplit
crVSplit
crMultiDrag
crSQLWait
crAppStart
crHBeam

どのようなカーソルかは マウスカーソル定数一覧 を参照してください。

これらのカーソルリソースは C++ Builder のもので Windows 標準では存在しないため非サポートとなります。
また、他のアイコンも C++ Builder とは少し見た目が異なります。
C++ Builder の指カーソルなどは特徴的なので、Windows 標準のものとの違いが分かりやすいと思われます。

なくなって困るカーソル画像は自分でリソースを準備する必要があります。

投稿者 Takenori : 02:45 | トラックバック

2013年04月26日

Window クラス仕様変更候補

Window クラスから削除や変更する予定のメソッドやプロパティです。
あくまで候補なので、変更が困る場合は、コメントや Twitter で意見をください。
あまり後の方だと対応できなくなるので、意見は早めにください。


削除予定
Window.layerLeft / Window.layerTop / Window.setLayerPos
Window.innerSunken
Window.maxHeight / Window.maxWidth / Window.setMaxSize
Window.minHeight / Window.minWidth / Window.setMinSize
Window.borderStyle
Window.showScrollBars
Window.setMaskRegion / Window.removeMaskRegion
Window.focusable
Window.beginMove
Window.showModal : 通常 Window をモーダル化するのは VCL の特殊実装で、通常ではモーダルウィンドウはないため。

Window にコントロールを配置せず、直接描画する形への変更に伴うものや、あまり標準的ではないもの、使われていなさそうなものを基準にリストアップしています。


変更予定
Window.imeMode : 読込みのみに変更(内部的に書き込みはコメントアウトされていたので、それを反映する)
Window.menu プラグイン化予定、それに伴いフルスクリーン時はメニュー表示不可。


変更の可能性があるもの
Window.drawDevice
Window.focusedLayer
Window.primaryLayer

描画システムをまるごとプラグインで入れ換えられることを検討しており、その変更に伴い変更される可能性があります。

これ以外にも開発が進むにつれて変更が入る可能性はあります。

----
以下のメソッド類は互換性維持して欲しいということなので、維持予定。
min/maxSize系
borderStyle
focusedLayer
showModal()

投稿者 Takenori : 01:01 | トラックバック

動画やグラフィック周りについて

Window.setMaskRegion を使って動画の上にダイアログを重ねるのに必要と言う話を元に検討していることについて。

ミキサー(VMR)モードであれば、テクスチャにレンダリングしているので、大元の描画自体を Direct3D 9 で行うのなら、レイヤーを動画上に持ってこられるため、回避可能。
オーバーレイは WMV 再生で上下反転して再生される問題が存在するため、現状非推奨。
KAG3 でオーバーレイ指定した場合は、VMR での再生が試みられた後、無理ならオーバーレイになる。
レイヤーモードは CPU 負荷が高いことだけが問題で、安定性や柔軟性、動画より上にレイヤーを重ねることに何ら問題はない。
Vista から新たに EVR と言う再生方法が追加されているので、新規に追加することも検討。

VMR での動画再生をレイヤーの上もしくは下に持っていける構造にするのなら、通常のレイヤー機構自体も、層状の構成が可能にしてしまうのが自然か。
Direct3D で、複数層重ねられて、その層ごとにプライマリーレイヤーを設定したり、動画再生を設定したりする形。
レイヤーの上位にさらにレイヤーが存在する形。

グラフィック周りの差し替え可能構造等も含めて検討する。

投稿者 Takenori : 03:16 | トラックバック

2013年04月28日

追加検討機能:ログへのグループとレベルの追加

ログへ32種類のグループと5種類(仮)のレベルを追加し、表示をマスクできるようにする。
ロググループは32bit値で、マスクを用いることで任意グループのログのみ表示可能にする。
また、ログにレベルを導入して、些細なものをマスクできるようにする。
たとえば、information、notification、warning、error、critical の5種類にして、一定レベル以上のみ表示するなど。
レベルごとにマスクを指定できるとなお良い。

要は大量に吐かれるログの内、目的のログを素早く見つけることが出来るように、必要なもののみ表示することを可能にする。
開発中システム関係で表示される information レベルのログは見えていても対して役立たないし、必要とするログが見つけづらくなったりする。
だからといってログを減らすのはあまり好ましくない。
そのような状況を解決するためにグループとレベルを導入して両方の問題の解決を図る。

投稿者 Takenori : 04:43 | トラックバック

2013年04月30日

コンソール

コマンドラインから起動された時、ログをコマンドラインに流す対応は既に行った。
今までだと、Debug.console.visible = true; と言う一文を開発中は入れていたけど、今はコマンドラインから起動すればそこにログが流れるので、スクリプトに手を加えずにログを確認できる。
地味だけど便利。
ただ、今のところコマンドラインに入力されたパスがそのまま argv[0] に入る関係上、実行ディレクトリが期待通りにならず、コマンドはフルパスで入れないとうまく動かない。
その辺りは argv[0] からではなく、プロセスからパスを取得するように変更した方が良さそう。

コマンドラインからの実行でない場合、Debug.console.visible = true; とした時にコンソール作ってもいいかもしれない。
それと コマンドラインからの入力で何か行えるようにしてもいいかもしれない。
コマンドをスクリプトから登録して吉里吉里シェルでコマンド入力できたり、インタプリタモードになったりするような。
まあこの辺りはツールを作る時にあると便利かもしれない機能なので、すぐに実装することはないと思うが。

投稿者 Takenori : 17:42 | トラックバック

2013年05月01日

GitHub へ登録

GitHub 吉里吉里Zリポジトリ

ログをもらって履歴も含めて登録しようとあれこれしていたが、手間がかかりすぎるので諦めた。
結局もらったログ ( 2013/04/30 ) の状態からの差分で登録した。
これより前のログは公式の SVN リポジトリを参照すれば見られるので、それほど大きな問題はないと思う。

現在のソースコードは、ビルドを通すことと動かすことを目的に書いているので、汚い部分が多い。
一通り実装したら、プラットフォーム依存部分の抽象化なども含めて整理していく。

投稿者 Takenori : 23:21 | トラックバック

マンスリービルド

月に1回くらいはビルドをリリースしようということで公開。
2013/05/01 ビルド
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

GitHub 上のバイナリ - Release ビルドした時たまに更新する。

MIDI / CDDA / Pad / Menu クラスは削除されている。
正規表現は実装途中。
Continuous ハンドラとV-Sink待ちはまだ。
Window クラスから削除予定メソッドは未実装。
Window.ShowModal も未実装。
その他オリジナルと異なる部分もあると思われるが未確認。

現在のところ、単に VC ビルド版が動くことがわかる程度で実用性などはない。
このビルドについて不具合報告などされても、実装途中のため対応しない。

投稿者 Takenori : 23:46 | トラックバック

2013年05月18日

レイヤーとネイティブでのTJS2クラスの継承

吉里吉里2では、ネイティブで TJS2 クラスの継承は出来ない。
羽々斬で実験的にやってみたが、それほど難しくないので実装してもいいかもしれない。
基本的には、VM の InterCode~ クラスでやっているのと同じようなことを汎用化して、実装しやすくすればネイティブで任意クラスを継承したクラスを書ける。
KAG3 で、Layer クラスを継承した様々なクラスが書かれているが、いくつかのクラスをネイティブ化するなどある程度使い道がある。
ただ、Core ではなく、Plugin 側で出来るようになっていないと魅力減。

現在の Layer クラスは機能が多いので、分割整理する要望が上がっている。
大別すると位置等状態、イベント、画像データ実体、画像合成等加工処理の4つくらいか。
これは位置等状態+イベント、画像データ実体、画像合成等加工処理の3つに分割するのが妥当と考えているが、分割すると互換性が大きく失われる。
主要クラスである Layer が大きく変わってしまうのはあまり好ましくないと思っているのでどうしたものかと考えるわけだが、上述の継承が使えるのなら、ベースクラスを新設して、Layer クラスは互換性を維持する方針がとれる。
SuperLayer でも BaseLayer でもいいが、基底クラスを新設し、位置等状態+イベントをここに持たせ、画像データ実体(Bitmap or Image)、画像合成等加工処理(Canvas)の2つを担当するクラスを持つようにする。
SuperLayer を継承した Layer クラスを作り、互換性のためのメソッド等で Bitmap や Canvas へのアダプタとして機能するようにする。
このような構成にすれば、互換性は維持され、新規に作る場合は分割された構造を利用して拡張できる。
Core には Layer クラスを入れず Plugin 化されていた方が構成的にはすっきりする。
と、ここまで考えた段階で、Layer クラスはネイティブでなくても TJS2 で記述されていれば十分と気付いてネイティブ継承は自分の中で霧散した。
それよりも TJS2 to C++ を作った方がとも考えるが、それをやろうとしたらどっちみちネイティブ継承は必要になる。
TJS2 to Java を試作した限りでは、C++ へのトランスコードの方が楽に思えた。
JIT よりも作りやすいかもしれない。

可能性としてこのようなことを検討しているが、どうするかはまだ決めていない。

投稿者 Takenori : 20:25 | トラックバック

2013年05月21日

メニューをプラグイン化

コアからメニュー機能を削除し、プラグインに移動した。
ゲームではメニューは非推奨機能となって、主にツール用途で使われることを想定している。
吉里吉里2 のゲームを Windows8 タブレットなどタッチデバイスでプレイする時、フルスクリーンでプレイすることになると思うが、その場合メニューは使えなくなる。
使えないことはないが、画面上端ギリギリをうまくタップしないとメニューを出せない。
今後 Windows8 タブレットがある程度普及することを考えるとゲームで標準のメニューは使いづらく、代替策を用意する必要がある。
ゲーム中でメニューに相当する機能を組み込むことになると思う。
吉里吉里Z は、これをほぼ強制することになる。
プラグイン化したメニュー機能はフルスクリーン時使えない。

その他仕様の差異は、ショートカットキーの文字列が API の GetKeyNameText で得られるもの準拠となったので、BkSp が Backspace に変わっている。
吉里吉里2のドキュメントで例に上がっているものでは変わらないはず。
実際に使えるキーの文字列は、menu プラグインの readme.txt にリストアップした。
ショートカットキーで機能するかどうかについてはまだ未調査。
後、内部処理的なイベントが InputEvent から通常の Event になったので若干タイミングが変わるケースが存在するかもしれない。
仕様の違いはこの3点のはず。
他に違いがあればそれは不具合か、認識漏れ。

メニュープラグインは、プラグインをロードすれば以前と同じように使えるので、基本的にロードメソッドコールの1行で互換になる(上述の変更点除く)。

メニューのエラーメッセージをリソースに移動して、日本語/英語と準備したので、メニュープラグインは多言語対応されている。
英語環境の Windows ではエラーが英語で表示されるはず。
これも仕様の違いとすれば、違いは4つ。

投稿者 Takenori : 04:15 | トラックバック

2013年05月22日

オプションデータをリソース化

吉里吉里2 では tvpwin32 の末尾に optionarea.bin を追加して、krkr.eXe とするが、吉里吉里Z はオプションをリソースに入れた。
optionarea.bin はマーカーがついたバイナリであったが、リソースであれば位置は特定できるからマーカーは不要。
optionarea.bin の実体はコマンドライン引数をカンマ区切りで列挙したものだから、バイナリである必要はないということでテキストファイルにしてしまった。
これでデフォルトオプションは楽に編集できるはず。
ただ、今までのオプション設定ツールとは互換性がなくなってしまうので作り直す必要がありそう。

投稿者 Takenori : 01:08 | トラックバック

2013年05月23日

KAGParser をプラグイン化

KAGParser クラスをコアから削除してプラグイン化した。
他のクラスと毛色の違う、どちらかといえばプラグインに適したクラスなのですっきり。
KAGParser クラスは、自分の中では吉里吉里2 の中で読みたくないソースコードナンバー1で、ちょっと触りたくない部分だったりする。
分離されることで KAG 以外の互換性が無いシステムを作るときは代替クラスをプラグインで作る時も思い切りやすくなったと思う。

投稿者 Takenori : 00:30 | トラックバック

プラグインのライセンス

吉里吉里2 リポジトリに入っているプラグインで、修正BSDライセンスにしても問題ないと言うプラグインのauthorは連絡ください。
プラグイン以外でもkwdigets等で修正BSDライセンスとして取り込んでも良いものについても同様に連絡ください。
修正BSDライセンスとして 吉里吉里Z リポジトリに取り込もうと思います。
一律取り込みしようと当初考えていましたが、ライセンス上問題がありそうなので許可の得られたもののみ追加したいと思います。

Deeさんとごうさん、三上さん自分がauthorのものについては、現在許可が得られているので順次追加していきます。

----

吉里吉里2 と同じようにリポジトリ集約する形を考えていたけど、GitHub のスタイルからすると、author がそれぞれリポジトリ持って開発する形の方が開発はしやすそう。
分離されている方がフォークしやすく、また取り込む場合は author にリクエスト出すことになるから、author がリポジトリ持っている方が手間がいらない。
分散することでややソースコード発見しづらくなるが、リンクがあればなんとかなる。
この辺りどういう管理スタイルが良いだろうか?
意見求む。

投稿者 Takenori : 18:33 | トラックバック

Layer クラスから削除するメソッド

ドキュメントに「このメソッドは旧式になりました。代わりに○○を使用してください。」と書かれている以下の6メソッドは削除予定です。

Layer.affineBlend
Layer.affinePile
Layer.blendRect
Layer.pileRect
Layer.stretchBlend
Layer.stretchPile

ドキュメントに記載されている代替メソッドに置き換えてください。
基本的に削除方針ですが、置き換えられないなど理由があれば連絡ください。

投稿者 Takenori : 22:48 | トラックバック

2013年05月26日

Unicode文字セット対応

吉里吉里Z を Unicode 文字セット対応した。
吉里吉里2 はマルチバイト文字セット。
C++ Builder2007 まではマルチバイト文字セットで、それ以降 Unicode 文字セットとなったよう。
9X 系ではマルチバイト文字セットだったが、9X 系非サポートなら Unicode 文字セットが標準的に使用されているので、変更した方が良いため変更した。
この変更に伴い、今までタイトルバーやメニューに表示できなかった Unicode 文字が表示できるようになった。

krkrtitle20130526.png

スクリプトを UTF-16 LE で書けば、文字コードの変換は発生しない。
多言語対応する場合は Unicode 文字セットの方が良い。

投稿者 Takenori : 22:53 | トラックバック

2013年05月28日

タッチイベント仕様について検討

マルチタッチ対応しているかどうかを取得するメソッド追加。
タッチイベントは有効化/無効化可能、イベントの TouchDown/Move/Up は別に作る。Clickは発生しない。
デフォルトで有効/無効はオプションにしてデフォルト有効。
有効化/無効化メソッドを行えるメソッドは別にあり。

これについて2種類の案をもらった。

1. onClick(マウスとタッチ両方で発生) onMouseDown(マウスで発生) onTouchEvent(タッチで発生)はどうか。
2. イベントオブジェクトに追加情報付ける。

2 の場合、onMouseDown/Up のボタンにタッチを追加。
onMouseMove の shift にフラグ追加。
マルチタッチ識別IDを引数に追加。
Clickあり。
と言う形か。

onClick は環境依存で問題も発生しやすく、確か LayerManager 辺りで down/click/up の順で発生しなければ不整合が発生したはず。
またクリックイベントは VCL の固有の機能。
そのため出来れば無くしていきたいが、マウスでのクリックではなくしづらい。
1 のケースでは、タッチ時クリックは無しにしたい。

2の案は互換性を保ち、新規機能も追加され良いように思えた。
が、マルチタッチ時のクリックはどうするのか?と言う問題に気付く。
指が離されるごとにクリックが発生するのか、最後の指が離されたときにクリックが発生するのか、それともクリックイベントは発生しないのか。

まず指が離されたときにクリックが発生すると、マルチタッチ時何度もクリックが発生することになる。
これは明らかに意図していない動作であろう。
最後に離されたときはどうか?
例えば CG モードでマルチタッチで拡大したいとする、CG モード時のクリックは次の CG へ切り換えとなっていることが多いが、この動作だと拡大して指離したと思ったら次の CG に切り替わって意図しない挙動をする。
シングルタッチやマウスのクリックでは次の CG に移って欲しいが、マルチタッチ時はそうなって欲しくない。
この様なことを考えるとマルチタッチ時はクリックイベントは発生しない仕様が良いように思える。

駅の券売機や ATM のタッチパネルでは、押した瞬間に反応する。
マウスは、多くの場合離した時に反応する。
タッチパネルで押した瞬間に反応するのは、高齢の人は反応するまで押し続けることがあるためと言う説がある。
ボタンの接触が悪かったりすること等からだろうが、テレビのボタンを考えると分かりやすい。
テレビのリモコンのボタンは反応するまで押し続けることが多い。
ボタンの延長線上であるタッチパネルのボタンも同じように押した瞬間に反応するようにしなければ、ずっと押したまま反応しないと誤解される可能性を考慮してこのような仕様になっていると言う話。
ただ、スマートフォンではスクロールなど押したときに反応すると対処できない機能があるため、離した時に反応するようになっていたりする。

クリックの話に戻る。
シングルタッチの時はクリックイベントを発生させるべきか?
リストのスクロールでは、スクロールした時は指を離した時に選択動作は発生しない。
その場でスクロールせずに指を離した時は、選択動作が発生する。
この場合クリックが発生しても使えない。

もちろんクリックで反応した方が楽なケースもあるだろう。
でも、状況によって発生させたり、マルチタッチ時はなくなったりするのであれば、初めからクリックイベントを無くしてしまい、離した時のイベントでアプリケーションごとに適切に処理する方が好ましいと考えられる。

クリックの問題はだいたいこんなところだろうか。
そして最初の仕様。
フラグやボタンの種類で分けて、タッチの時はクリックイベントなしでも良いかもしれないが、マルチタッチはタッチのみでタッチとマウスで操作を分けることを考えると、タッチイベントを別に追加して、互換性のためにタッチイベントをなしに出来るようにする形が良いのではないかと考えている。

と言うことで最初に書いた仕様にしようと思っているが、何か問題等あるだろうか?
もしくは、よりよい仕様はあるだろうか?


追加仕様として、イベント以外に状態を取得できるようにしたいと考えている。
マルチタッチは、イベントごとにタッチの識別子が付与され見分けられるようになっているが、この識別子をキーとした辞書で、最初に押された座標、現在の座標、直前の座標情報を得られるようにする。
マルチタッチで各種ジェスチャーを処理しようとしたら、この辺りの情報を保持する必要があるので、あらかじめ内部で保持して取得できるようにしておこうというもの。

投稿者 Takenori : 02:07 | トラックバック

2013年05月29日

マルチタッチ実装中

Window クラスに onTouchDown/onTouchUp/onTouchMove/onTouchScaling/onTouchRotate を実装した。
onTouchScaling/onTouchRotate は拡大率/角度と中心点がイベントで飛んでくる。
拡大/回転認識閾値もプロパティとして持った方が良さそう。
上が動作動画。
まだまだネイティブ側 TJS2 側共に調整が必要。
TJS2 側は、テストなので作り込まないが。

投稿者 Takenori : 03:12 | トラックバック

2013年06月01日

5月末バイナリ

krkrz_20130601.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

マルチタッチのサンプルがついている。
onTouchScaling/onTouchRotate/onMultiTouch 周りのイベント通知に付いては再考中で、変更の可能性がある。
readme.txt 参照のこと。

GitHub Pages でマニュアルページを作った。
吉里吉里Java のパッケージ用に取ったドメイン割り当てたけど、独自ドメインじゃない方が良かったかも。
永続性を考えると。

マニュアルページはまだ整合性が取れていない部分もある。
順次更新していく。
Git でページを更新していけるので、GitHub Pages は楽。

投稿者 Takenori : 00:40 | トラックバック

タッチパネル付き液晶の罠

マルチタッチ対応したゲームを開発するには、マルチタッチ対応タッチパネル付き液晶が必要になってくるが、マルチモニタに対応していない液晶もあるから注意。
タッチパネル付き液晶をセカンダリモニタにして開発しようとしても出来ない。
仕様に小さく書いてあったりする。
吉里吉里Z とは関係ないけど、私がこの罠にはまったので書いておく。

投稿者 Takenori : 01:37 | トラックバック

2013年06月13日

プリレンダーフォント新フォーマット案

現在のプリレンダーフォントファイルはそのままサポートしつつ、プリレンダーフォントファイルを作るツールを作りやすくするために Dictionay/Array Binary を検討中。
従来のテキスト形式だと重くて使えないが、バイナリ形式であれば、実用的な速度で使えると思われるので、Dictionay/Array Binary ファイルに保存/読込みを行い、描画等可能にする。
テキスト形式で概念的なファイルフォーマットを記述すると以下のような形。

%[
 "FileType" => "PrerenderdFont",
 "Version" => 1,
 "NumberOfGlyph" => 10,
 "glyph" => %[
  "a" => [
   10, // width
   10, // height
   10, // originx
   10, // originy
   10, // incx
   10, // incy
   10, // inc
   <% 00 00 ... %> // bitmap
  ],
  "b" => [
   10, // width
   10, // height
   10, // originx
   10, // originy
   10, // incx
   10, // incy
   10, // inc
   <% 00 00 ... %> // bitmap
  ],
  ...
 ],
]

この形であれば TJS2 で扱うことも出来る。
このようなファイルを TJS2 で作るために、以下のようなメソッドを追加。

Font.getGlyph( code:int ) : Array の様なメソッドを追加。
配列は、以下のような形で返ってくる。
[
 10, // width
 10, // height
 10, // originx
 10, // originy
 10, // incx
 10, // incy
 10, // inc
 <% 00 00 ... %> // bitmap
]

後は、Octet をビットマップとみなして、Layer に描画出来れば、TJS2 で文字描画をかなり細かく制御できることになる。
単純にツールを kwidgets/TJS2 で作りやすくすることを目的に仕様を考えていたが、プリレンダーフォントは外字的に手軽に使いたいと言う要望を聞いて、Octet を直接 Layer に描画できれば、その要望は叶えられるなとも考えた。
Octet の描画は置いておいて、それ以外の部分については代替ツールを作る段階で実装を行ってみる予定。
速度的な問題がなさそうであれば、追加機能としてそのまま残す予定。

投稿者 Takenori : 21:03 | トラックバック

2013年06月15日

プリレンダーフォント

プリレンダーフォントは mapPreRenderedFont せずに外字的使い方で手軽に使える方法が欲しい。
サイズ固定なので拡縮して表示するのが難しい。
と言う要望があった。
後、前回のフォーマット案で、Dic/Array Bin は、以下のようにして呼び出す形なら、glyph に適当なクラス入れて missing で配列返せば動的にフォント画像を生成できる? と言う話も。
Font.mapPrerenderdFont ( PrerenderdFont形式辞書 )
それなら glyph クラスの基本形を定義してしまえば、フォント周りは全部それで対応できる。

マップせずに使える方法となると、以下のようなメソッドを準備し、glyph に前回のフォーマット案の glyph の配列を渡す形にすれば、単体で呼び出しやすい。

Layer.drawGlyph(x, y, glyph, color, opa=255, aa=true, shadowlevel=0, shadowcolor=0x000000, shadowwidth=0, shadowofsx=0, shadowofsy=0)

glyph : Array[8]
[
10, // width
10, // height
10, // originx
10, // originy
10, // incx
10, // incy
10, // inc
<% 00 00 ... %> // bitmap
]

拡大縮小は、その配列を生成するメソッドをプラグインなどで実装すれば実現可能になる。
Dic/Array Bin を利用したフォーマットであれば、以下のようにして1文字描画は簡単に行える。

PrerenderdFonts = Scripts.eval("NewPrerenderdFontFile.bin");
function drawChar(x, y, ch, color, opa, aa, shadowlevel, shadowcolor, shadowwidth, shadowofsx, shadowofsy)
drawGlyph( x, y, PrerenderdFonts.glyph[ch],...);
}

複数文字を同時描画するときは一手間必要になるが、KAG のメッセージは1文字ずつ書いているので、それを使って複数文字書けばいいだけではある。
もう一つ、最初全て統一的に扱えると思われた部分が統一的ではなくなってしまうことが残念。
Font.getGlyph( code:int ) : Array メソッドを使い Glyph 配列を生成してから渡せば全て統一的に扱える手段が提供できるが、内部的には2種類の描画方法を持つことになる。
互換性等の都合から、この追加する方法と従来の方法 2種類持つのは仕方ないか。
従来の方法で指定できるプリレンダーフォントファイルは今までのもので、新フォーマット案は組み込みの機能ではなくなるので、あくまで参考仕様と言った形になるかな。

後、この形であるのなら glyph 配列にはカラー情報も追加して、グレースケール65色、256色、フルカラーの指定が出来ると外字として扱いやすいはず。

投稿者 Takenori : 03:29 | トラックバック

マルチディスプレイ対応に伴う仕様変更

マルチディスプレイへの対応で若干の仕様変更を考えている。
考えているというか、もう実装してしまった。

System.desktopLeft/Top/Width/Height は、全てのディスプレイを合わせたサイズを返す。
System.screenWidth/Height は、メインウィンドウがあるモニタのサイズを返す。メインウィンドウが作られる前はプライマリモニタのサイズで返す。

この用に実装を変えた。
これで問題があると言われれば元に戻すが、特にないようであればこの形にしたいがどうだろうか?
今までは両方プライマリモニタでサイズを返すと言う実装になっていて、なんとなく違和感がある形であったが、上記変更した仕様であれば、感覚と一致するのではないかと思う。

各モニタに関する情報は WindowEx.dll で得られるようなのでそちらで。
monitor.dll を作った方が良いかとも思っていたけど。

2013/12/02
再度仕様変更。
System.desktopLeft/Top/Width/Height は、メインウィンドウがあるモニタの作業領域を返す。
メインウィンドウがない時は、プライマリモニタの作業領域を返す。

投稿者 Takenori : 03:52 | コメント (4) | トラックバック

2013年07月03日

7月頭バイナリ

krkrz_20130702.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

文字のラスタライザが FreeType か GDI を選択できるようになった。
Layer.font.rasterizer = frFreeType/frGDI;
現状 Layer はインスタンスでないと指定できない。

他に細かいバグフィックスや未実装であった機能の実装を行っている。
後、環境依存部分の分離を進めているけど、外側からはわからない。

投稿者 Takenori : 01:52 | トラックバック

2013年07月04日

サブセット

吉里吉里2 の環境固有部分の分離と集約化を進めている段階で、全てをそのようにするには手間がかかるし、マルチプラットフォーム化を見据えた対応としてもあまり筋が良くないように思えあれこれ考えていたけど、サブセットを定義する方法を思い付いた。
吉里吉里2 の機能はゲームのみを作る場合冗長すぎる。
その冗長な部分が幅広い用途や柔軟性を生み出しているんだけど、それが逆にマルチプラットフォーム化の足かせになっている。

たとえばすべてのフォルダパスを扱えるようになっているが、実際にゲームで必要なものはゲームデータとセーブデータへのアクセス。
PC (Windows) ではこれらの取り扱いが煩雑なのでパスを柔軟に操作できた方が良いが、他の環境下ではゲームデータかセーブデータに限ってアクセス出来るようになっていた方が作りやすいし、うまくやってくれるのなら置かれる場所はどこでもいい。
PC では、なかなかそうはいかないが。

また、Android 等スマフォやタブレットはウィンドウなどはなく基本フルスクリーンなので、描画領域取得と想定解像度辺りが指定できれば事足りる。
設定に従って勝手にレイヤーを表示してくれれば楽。
ウィンドウ周りを扱うのは PC の事情。

そのように考えると基本的には、グラフィック、サウンド、ムービー、ゲームデータ、セーブデータ、操作系の 6つがあれば事足りる (スクリプトは TJS2 がある前提)。
このような必須と成りうる機能のみで構成されたサブセットを定義し、このサブセットに該当する部分のみ環境固有部分の分離と集約化を行い、マルチプラットフォーム化を行う場合、ここだけ環境ごとに実装すれば、マルチプラットフォーム化の労力は少なくて済む。

吉里吉里Z で仕様からレガシーな機能を削って少しスリム化したけど、それでもまだまだ機能が多いので、この様なことを考えている。
PC では、ツール用途のための機能の存続などもあるし。
実際のところ、これによって Windows 用吉里吉里Zの何かが変わると言った事はなく、単にフォルダ構成やデバッグオプション、抽象化されている部分が減るという影響があるだけなんだけど。

投稿者 Takenori : 17:40 | トラックバック

2013年07月29日

Layer クラスの分割

Layer クラスの分割と書いたけど、従来の Layer クラスはそのまま残すことにした。
分割して、TJS2 層で互換性をとることも検討したけど、そのまま残した。
つまり、いくつかクラスが追加されただけ。
以下追加されたクラス(一部実装中)。

class Bitmap {
function Bitmap()
function Bitmap( width : int, height : int, bpp = 32 : int )
function Bitmap( filename : string, colorkey = clNone : int )
function getPixel( x : int, y : int ) : int
function setPixel( x : int, y : int, value : int )
function getMaskPixel( x : int, y : int ) : int
function setMaskPixel( x : int, y : int, value : int )
function independ( copy = true : boolean )
function setSize( width : int, height : int )
function copyFrom( src : Bitmap )
function save( filename : string, type = "bmp" : string )
function load( filename : string, colorkey = clNone : int ) : Dictionay
function loadAsync( filename : string, colorkey = clNone : int ) : bool
property width { set/get }
property height { set/get }
property buffer { get }
property bufferForWrite { get }
property bufferPitch { get }
property loading { get }
}

画像情報を保持するクラスがあるとツール用途などで助かるということで追加。
後、追加検討途中だけどパレットも考えている。
bpp が 8 で、256色の時パレットを扱えるようなもの。
ただ、そのままでは描画出来ないので、32ビット画像へ描画するメソッドも検討中。

class Rect {
function Rect();
function Rect( left : int , top : int , right : int, bottom : int );
function Rect( src : Rect );
function setSize( width : int, height : int );
function setOffset( x : int, y : int );
function isEmpty() : bool
function clip( r : Rect ) : bool
function union( r : Rect ) : bool
function intersects( r : Rect ) : bool
function included( r : Rect ) : bool
function equal( r : Rect ) : bool
property width { set/get : int }
property height { set/get : int }
property left { set/get : int }
property top { set/get : int }
property right { set/get : int }
property bottom { set/get : int }
property nativeArray { get : tjs_int[4] } // for plugin
};

描画系のメソッドを別クラスで作るにあたり、矩形クラスがないと不便ということで追加。

class ImageFunction {
void operateAffine( dst, src, A, B, C, D, E, F, srcrect=null, cliprect=null, affine=true, mode=omAlpha, face=dfAlpha, opa=255, type=stNearest, hda=false)
void operateRect( dst, dleft, dtop, src, srcrect=null, cliprect=null, mode=omAlpha, face=dfAlpha, opa=255, hda=false )
void operateStretch( dst, src, dstrect=null, srcrect=null, cliprect=null, mode=omAlpha, face=dfAlpha, opa=255, type=stNearest hda=false )

void flipLR( bmp, rect=null )
void flipUD( bmp, rect=null )

void adjustGamma( bmp, rgamma=1.0, rfloor=0, rceil=255, ggamma=1.0, gfloor=0, gceil=255, bgamma=1.0, bfloor=0, bceil=255, cliprect=null, isaddalpha=false)
void doBoxBlur( bmp, xblur=1, yblur=1, cliprect=null, isalpha=true);
void doGrayScale( bmp, cliprect=null )

void colorRect( bmp, value, opa=255, rect=null, face=dfAlpha, cliprect=null )
void drawText( bmp, x, y, text, color, opa=255, aa=true, face=dfAlpha, shadowlevel=0, shadowcolor=0x000000, shadowwidth=0, shadowofsx=0, shadowofsy=0, hda=false, clipRect=null )
void fillRect( bmp, value, rect=null, isalpha=true, cliprect=null )
};

組み込みの画像処理系のメソッドをまとめたクラス。
クラスと言っても全て static なので、単なる関数の集まり。
更新された矩形を返した方が良いと思い、現在少し変更中。

これらのクラスを使って、Layer のようなクラスを作れなくはないけど、たぶんだいぶ効率が悪い。
Bitmap を継承したクラスに ImageFunction のメソッドをくっつけた方が使い勝手が良いかもしれない。

後、Layer クラスから Bitmap を得る方法を参照にするかコピーにするか検討中。

投稿者 Takenori : 14:59 | トラックバック

2013年08月01日

ネイティブでの TJS2 クラスの継承

ネイティブで TJS2 クラスの継承可能な処理を入れた。
ただ、C++ では継承関係はないので、実装は面倒な形に。
TJS2 Class 側にスーパークラスのポインタ保持、TJS2 インスタンス側にスーパークラスのインスタンス保持と言う形。
仮想コードで書くのならこんな感じ。
NativeClass.SuperClass = SuperClass::NativeClass;
CustomObject.SuperClass = SuperClass::CustomObject;

iTJSDispatch2 は ClassInstanceInfo の TJS_CII_GET_SUPRECLASS/TJS_CII_SET_SUPRECLASS で設定取得する。
現在のところ多重継承はサポートしていない。
C++的な継承関係はないので、実装は少し面倒。
同一バイナリであれば、TJS2 で親クラスに当たる NativeInstance を包含することで少しは記述が楽だけど、バイナリが異なると FuncCall 経由で呼び出すことになるので面倒。
TJS2 のコンストラクタの呼び出し順は基底クラスが先。
コンストラクタ呼び出し時には、スーパークラスが登録されているので、そこで親の NativeInstance を取得して、保持しておくことが出来る。
NativeClass へのスーパークラス登録は、global から目的のクラスを取得して設定する。

同一バイナリ内に限定するのであれば、C++ で NativeInstance を継承してしまうのが良いように思うが、そのままだと基底クラスと派生クラスが NativeInstance をそれぞれ持ち、基底クラスのメソッドでアクセスした時は、基底クラスの NativeInstance が使われ別々のインスタンスにアクセスすることになって意図しない動作を引き起こす。
派生クラス側の NativeInstance を両方に登録するば、この問題は解決するが、NativeInstance 解放時に二重解放の問題を引き起こす。
NativeInstance はリファレンスカウンタ等で管理されていないので、二重解放の問題を回避するべく NativeInstance にもリファレンスカウンタを導入するとなると、全プラグインに波及する。

CustomObject 側ではスーパークラスを持たず、スーパークラスのメンバを登録した後、派生クラスのメンバを登録して上書きすれば、NativeInstance の二重登録問題は解決する。
NativeInstance 取得時に基底クラスの ID でも取得でき、IsInstanceOf で基底クラスの名前でも true を返せば、オーバーライド時に直接的に基底クラスのメンバへアクセスできないことを除いて、問題は解決する。
直接的にというのは、global 経由であれば、アクセスできるので不可ではない。
問題はバイナリが異なると継承できなくなること。

他にも方法を考えたが、結局一番上に書いた方法で実装した。
実装の面倒臭さはProxyクラスを作って継承するなどすればある程度緩和されるが、Proxyクラスを作るのが面倒なことには変わりない。

投稿者 Takenori : 14:49 | トラックバック

2013年08月05日

8月バイナリ

krkrz_20130805.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

Bitmap クラスなどが追加されているが、テストしていないので正しく動くかはわからない。
非同期読込みはまだ追加していない。

投稿者 Takenori : 22:47 | トラックバック

2013年08月27日

pack/unpack の追加

バイナリを処理可能にするメソッド pack/unpack を Array/Octet に追加。
それぞれ Array.pack(template)/Octet.unpack(template) ( Octet はパリアント型の内部型 )。
これらメソッドは perl/Ruby で実装されているもので、テンプレート文字列に従い、バイナリを分解/構築するもの。

pack は Array 要素を引数の template に従い、バイナリ化し、Octet 型の値を返す。
unpack は Octet が保持するバイナリを引数の template に従い、配列化し、Array クラス型の値を返す。

template で指定される型は以下の通り。

a : ASCII 文字列(ヌル文字が補完される)
A : ASCII 文字列(スペースが補完される)
b : 2進数文字列(下位ビットから上位ビットの順)
B : 2進数文字列(上位ビットから下位ビットの順)
c : 符号付き1バイト数値(-128 ~ 127)
C : 符号無し1バイト数値(0~255)
d : 倍精度浮動小数点値
f : 単精度浮動小数点値
h : 16進数文字列(low nybble first)
H : 16進数文字列(high nybble first)
i : 符号付きint数値(通常4バイト)
I : 符号無しint数値(通常4バイト)
l : 符号付きlong数値(通常4バイト)
L : 符号無しlong数値(通常4バイト)
n : 符号無しshort数値(ネットワークバイトオーダ)
N : 符号無しlong数値(ネットワークバイトオーダ)
s : 符号付きshort数値(通常2バイト)
S : 符号無しshort数値(通常2バイト)
v : 符号無しshort値(リトルエンディアン)
V : 符号無しlong値(リトルエンディアン)
x : ヌル文字/1バイト読み飛ばす
X : 1バイト後退
@ : 絶対位置までヌル文字を埋める/指定位置まで移動
m : Base64 encode / decode

template に使用可能なのは、上記文字と数値、'*'のみです。
カッコを使った繰り返しなどは未サポート。
現在のところサポートしているのは上記タイプのみですが、いくつか追加される可能性があります。
例えば、エンディアン固定の浮動小数点値等。
仕様については、perl/Ruby との差異により変更される可能性があります。

Octet の+演算しによる結合は出来るが、現在分割が出来ないのがやや不便かもしれない。
'@' による位置指定で読込みは可能。
バイナリ読込みは BinaryStream プラグインで出来ると思われる(未確認)。

投稿者 Takenori : 02:00 | トラックバック

2013年09月04日

リリースまでの予定

ソースコードの整理、ビルド環境の整理、実装漏れの確認を行った後、テストの予定。
テストの完了は、10月末の予定で、そこでβ版公開。
β版だけど、テスト完了したバイナリで、実質的には納品物。
瑕疵担保は、テスト中の2ヶ月としていたけど、延長して12月末まで受け付けることに。
(実際はその後も不具合があれば、対応可能な範囲で修正する)
テスト完了バイナリでテストしないと他の不具合に引きずられて確認しづらいであろうということから、こういう形にしたので11月から動作確認した方が面倒は少ないはず。
それが終わったら、1.0の正式版を12月末にリリース予定。

予定
10月末 β版公開
12月末 1.0公開

瑕疵担保責任期間がテスト後2ヶ月まで延長されるなんて、契約書と違うからダメだ、という人がもしいれば言ってくれればその人からは、テスト期間の2カ月間以降不具合の申し出があっても受け付けないので言ってください。そんな人がいるとは思えないけど、一応。

後、9月バイナリ置いておく
krkrz_20130903.zip

投稿者 Takenori : 01:21 | トラックバック

2013年09月21日

PNG/JPEG/TLG保存機能

従来の Bitmap 保存機能に加え PNG/JPEG/TLG 保存機能を追加。
以下の各種メソッドの type で指定する。
Layer.saveLayerImage(name, type="bmp")
Bitmap.save(name, type="bmp",meta=null)

JPEG で保存する時
jpg の後にクオリティーを指定する。
"jpg" とだけ指定した場合は、90% が指定される。
例)
"jpg010" : 10%
"jpg100" : 100%
"jpg080" : 80%

PNG で保存する時
png の後に 24 ビットカラー時は 24 を付ける。
"png24" : 24 ビットカラー保存
"png" : 32 ビットカラー保存

TLG5/TLG6 で保存する時
png の後に 5 か 6 を、その後に 24 ビットカラー時は 24 を付ける。
"tlg524" : 24 ビットカラー TLG5 保存
"tlg5" : 32 ビットカラー TLG5 保存
"tlg624" : 24 ビットカラー TLG6 保存
"tlg6" : 32 ビットカラー TLG6 保存

TLG で保存時は、Layer.saveLayerImage で呼び出された場合、以下の情報がタグ情報として保存されます。
Layer.type は、mode に保存されます。
Layer.imageLeft は、offs_x に保存されます。
Layer.imageTop は、offs_y に保存されます。
Bitmap.save では、meta がそのままタグ情報として保存されます。
meta は、Dictionary クラスを渡します。

投稿者 Takenori : 00:23 | トラックバック

2013年09月22日

Layer と Bitmap クラスの連携

コピーでやりとりする実装とした。
具体的には以下のメソッド。

Layer.copyToMainImage( bmp : Bitmap )
対象レイヤーのメイン画像を bmp へコピーします。
コピーといっても、変更されるまでは単なる参照のため、このメソッドの実行はすぐに終わります。

Layer.copyFromMainImage( bmp : Bitmap )
bmp の画像を対象レイヤーへコピーします。
コピーといっても、変更されるまでは単なる参照のため、このメソッドの実行はすぐに終わります。


Layer のプロパティで直接 Bitmap クラスへ参照アクセスする方法も検討したが、非同期読込みで問題になる、もしくはブロックが多発するため、コピーアクセスとした。
Bitmap クラスの非同期読込みであれば、影響範囲が少ないので非同期読込み中のアクセスは例外発生させてブロックする等がしやすい。

投稿者 Takenori : 00:44 | トラックバック

TJS2 スクリプトでの吉里吉里2と吉里吉里Zの判別方法

TJS2 のプリプロセッサで kirikiriz が 1 になるので、静的に切り換えるものはこれで切り換え可能。
ただし、バイトコードバイナリ化したものの場合、バイトコード化した段階でプリプロセッサに従いバイトコードが生成されるため、切り換えることが出来ない。
テキストのスクリプトで格納している場合は何ら問題ない。

動的に判別する方法として System.versionInformation プロパティは吉里吉里2では "吉里吉里[きりきり] 2 実行コア~" となっているが、吉里吉里Z では "吉里吉里[きりきり] Z 実行コア~" となっているので、判別可能。
後、バージョン文字の変更点として System.versionString は、1.0.0.001 を返す。
吉里吉里Z になったことでバージョンがリセットされているので、2.X.X.XXX 等を期待している場合は注意が必要。

投稿者 Takenori : 01:12 | トラックバック

2013年10月02日

ツールチップの仕様変更

Layer.hint で表示されるもの。
吉里吉里内ではヒントと呼ばれている。
VCL のツールチップはコモンコントロールのツールチップとは別実装で振る舞いが違うこととタッチ操作ではツールチップ自体表示されないと言うことから一時ツールチップ機能は無効にしていたものの、なくすのはまずいかと悩んで放置していたままになっていた。
どうするか再考し、少し仕様を変えて実装した。

仕様としては以下

ヒントを設定し、カーソルが一定時間停止しヒント表示タイミングになると Window.onHintChanged(text:string,x:int,y:int,isshow:bool) イベントが発生する。
カーソル停止時間は、property:Window.hintDelay で指定可能。
デフォルトは 500 (msec) 。
この値は元々の値と同じはず。
従来は固定値だったものを変更可能にした。
ヒントを描画するレイヤーには property:Layer.ignoreHintSensing を有効にして、ヒント表示を無視させる。

これで onHintChanged で isshow が true の時、ヒントを最前面レイヤーに描画し、ヒントレイヤーはマウスメッセージは無視されるように設定すれば従来と同じような表示が出来る。
isshow が false でイベントが来たら非表示にする。

従来は、標準の味気ない表示のみだったが、レイヤーに任意に描画可能としたことで、文字のみではなく画像などを用いて表示も可能となるので、良いのではないかと思うが、互換性を維持しようとしたら少し TJS2 スクリプトを記述する必要がある。

この仕様で互換性とれるし、表示変更できるので問題ない?

追記:
互換性を取るための TJS2 スクリプトは公開予定。
テストのためにほぼ互換のものは作成済み。
色とフォントが少し違うので、その辺りはもう少し VCL を追って調査し、ほぼ同じにする予定。

投稿者 Takenori : 03:34 | トラックバック

2013年10月09日

10月のマンスリービルド

krkrz_20131009.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

少し遅くなったけど置いておく。

投稿者 Takenori : 03:52 | トラックバック

2013年10月31日

吉里吉里Zでの吉里吉里2からの変更点一覧

変更
1. VCL 依存部分を Win32 API 呼び出し処理へ変更。
2. Direct3D7 を Direct3D9 へ変更。
3. フルスクリーン化処理を DrawDevice で行うように変更。
4. KAGParser クラスをプラグインに変更。
5. Menu クラスをプラグインに変更。
6. 各種依存ライブラリを更新。
7. 正規表現エンジンを鬼車へ変更。
8. コンソールへの出力をコマンドラインへの出力へ変更、デバッグ時はデバッグ出力へも出力。
9. Font クラスを生成できるように変更。
10. ツールチップ処理の仕様変更。
11. ゲームパッドの有効/無効をデバッグオプション化。
12. JPEG デコード時 LLM を使用するのを標準に。
13. TJS2 スクリプトのデフォルト文字コードを UTF-8 に変更。
14. ソースコード埋め込み文字列をリソースへ移動。
15. コンパイル後バイナリに結合していたオプションをリソースに移動。
16. マルチディスプレイ対応に伴いスクリーンサイズ等が返す値を変更。
17. フォント選択ダイアログをスクリプト化。
18. 文字入力ダイアログをスクリプト化。
19. 起動時ファイル選択ダイアログをフォルダ選択ダイアログへ変更。
20. 起動時ファイル選択をデバッグオプションで無効化可能に変更。

削除
1. コンソール削除
2. コントローラー削除
3. MIDI / CDDA / Pad クラス削除
4. Win9X 系メソッド削除
5. マルチバイトコードからワイド(UNICODE)バイトコードへ変更。
6. DirectDraw 描画処理を削除
7. ERI フォーマットのサポートを削除
8. Window クラスのいくつかのメソッドを削除。
9. Layer クラスの obsolete メソッドを削除。
10. マウスカーソルの内 Windows 標準でサポートされないものを削除。

追加
1. マルチタッチ機能のサポート。
2. Image/ImageFunction/Rect クラス追加。
3. Octet の pack/unpack の追加。
4. -startup="xxx" により任意スクリプトからの起動を可能に。
5. 5ボタンマウスの「戻る」「進む」キーサポート。
6. バックグラウンドでの画像読込み機能サポート。
7. TJS2 クラスの継承をネイティブ( C++ ) で記述可能に。
8. drawGlyph を追加し外字を描画しやすくした。
9. PNG/JPEG/TLG 保存機能の追加。


詳細については後ほど記載。

投稿者 Takenori : 22:21 | トラックバック

2013年11月01日

吉里吉里Z β1 バイナリ

krkrz_20131101.zip
krkrz_20131102.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。


不具合、仕様上の問題がある場合は、TwitterGitHub 等で連絡ください。


予定していた機能 ( 吉里吉里Zでの吉里吉里2からの変更点一覧 ) の組み込みは完了しています。
予定しているテストは未完了です。
テスト、バグフィックスを行いながら β2、β3 と更新していきます。
テスト完了でβ版とする予定でしたが、テストは間に合っていません。

契約上の期限2013年12月末を超えることはないと思いますが、前回提示した予定より遅れています。

残りの作業は、
テスト。
ドキュメントの更新。
XP3 で 2GB超えるとエラーで読み込めなくなる件の対応。
エンジン設定ツール作成。
です。

追記: 2013/11/02
XP で起動しなかった問題を取り急ぎ修正。

投稿者 Takenori : 00:47 | トラックバック

非同期読込み

非同期読込みは Bitmap.loadAsync(filename) と Bitmap.onLoaded(meta,async,error,message) を使って行う。
サンプルは GitHub のここ にある。

loadAsync で読込みを要求し、onLoaded で読込み完了を受ける。
非同期読込み中かどうかは Bitmap.loading で判定できる。
非同期読込み中は Bitmap の他のメンバへアクセスすると例外が発生する。
loadAsync の引数 filename は拡張子を含んだものとなり、省略できる Layer.loadImages とは異なるので注意。

onLoaded で受け取る各値 (meta,async,error,message) はそれぞれ以下の通り。
meta : Layer.loadImages の戻り値で受け取れるものと同じ。タグ情報の辞書配列。
async : 非同期で読み込まれたものかどうか。キャッシュに入っていた場合は、読込み要求した後そのまま onLoaded で返ってくる。
error : 読込みエラーが発生したかどうか。
message : エラーメッセージ。エラーが発生した場合、エラーメッセージが渡される。

読み込んだ画像は Layer.copyFromBitmapToMainImage(Bitmap) によって、Bitmap から Layer にコピーできる。
コピーと言っても、変更されるまでは共有されているので、一瞬で終わる。
読込み処理は非同期であるため、読込みが完了した時に、その画像を渡す Layer が既に無効化されている可能性がある。
onLoaded で他のオブジェクトへアクセスする場合は、無効化されていないか確認した方が良い。
もしくは、onLoaded が完了するまで無効化されないようにする必要がある。

投稿者 Takenori : 04:50 | トラックバック

2013年11月07日

吉里吉里Z β2 バイナリ

krkrz_20131107.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

いくつかの不具合を修正してβ2をリリース。
詳細については添付の readme.txt を参照してください。

β版はウィークリーでリリース予定です。
その週に特に変更がない場合はリリースしません。

ダウンロードページを GitHub グループ の krkrz で作成しました。

投稿者 Takenori : 23:46 | トラックバック

2013年11月10日

showModal 等で顕在化する Access Violation

本不具合は、偶発的にメモリ破壊を起こしうる問題で安定性に影響するため、β3は予定よりも早く出します。


【不具合概要】
TJS2 VM は関数が呼ばれると Variant 型配列のレジスタが確保される。
レジスタの確保は、配列から切り出して行う。
変数など、このレジスタが使われる。
GC は、このメモリ配列の切り詰めを行う。
この処理に不具合があった。


【解析結果】
tTJSVariantArrayStack で Current は Arrays 配列の要素のアドレスを指している。
void tTJSVariantArrayStack::InternalCompact(void) の中で realloc し Arrays を入れ換えているが、Current は変更されない。
以後、レジスタメモリの確保は、Current が指している Variant の配列要素がなくなるまで、もしくは全てが解放されきるまで、Current を基準に行われる。
当然、この Current は既に解放されてしまっている可能性があり、その場合 Arrays が保持している値とずれていく。
結果、たまに Variant へのアクセスでアクセス違反が顕在化することになる。

showModal によってこのアクセス違反が顕在化しやすかったのは……
1. showModal はウィンドウ表示中その関数は返らないので、tTJSVariantArrayStack の全てが解放されることはなく、Current の値が維持されたままになる。
2. showModal で別ウィンドウがアクティブ化し、メインウィンドウが非アクティブ化されることで、メモリのコンパクト化が走り、InternalCompact がコールされる。
この2点による。
実際にアクセス違反が顕在化するのは showModal 後に吉里吉里の非同期イベント処理で、Variant 内でかつリリースビルドのみとなっていたため、解析が困難であった(問題のある部分と離れている)。

【修正方法】
realloc された時に Current も同時に変更する。


この問題は吉里吉里2 からあったものであるが、吉里吉里2 では顕在化しない様子。
BCB の realloc では確保済みメモリよりサイズが小さい場合、再割り当てが行われないのかもしれない。
絶対に発生しないのかどうかは不明。

投稿者 Takenori : 21:10 | トラックバック

2013年11月11日

吉里吉里Z β3 バイナリ

krkrz_20131111.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

showModal 等で顕在化する Access Violation で書いた通り、β3を予定を繰り上げて公開します。

詳細については添付の readme.txt を参照してください。

投稿者 Takenori : 04:46 | トラックバック

2013年11月19日

吉里吉里Z β4 バイナリ

krkrz_20131119.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

今回、意見や提案に基づき以下の2点仕様が変更されています。

・KAGParser.dll の文字コードは UTF-8 をデフォルトとし、readencoding の指定に従う。
・PassThroughDrawDevice を削除し、BasicDrawDevice を追加、描画は Direct3D9 のみに。

これらの仕様に依存している箇所は修正が必要になります。

投稿者 Takenori : 04:45 | トラックバック

2013年11月23日

TJS2 オブジェクトのハッシュテーブル初期値を大きくすると速くなるのか

大きくするとかなりの速度向上が見込めると思い込んでいる人がいるようなので計測。
羽々斬の時、高速化するためテーブルサイズは変更してみたが特に効果はなかったと記憶しているが再度計測して記録に残す。

KAG3 の初期スクリプト実行時間(WindowやLayerが生成初期化される)を計測。
その直後のメモリ使用量も計測。
メモリ使用量はGetProcessMemoryInfo で得た WorkingSetSize を使用。
速度は6回実行して、最初の1回は除いた5回の平均時間。
括弧内は5回のそれぞれの結果。

HASH BITS 2 - 204.8(213, 184, 215, 219, 193)ms - 27,041,792byte
HASH BITS 3 - 199.4(190, 224, 189, 193, 201)ms - 27,037,696byte
HASH BITS 4 - 192.6(196, 195, 184, 200, 188)ms - 27,148,288byte
HASH BITS 5 - 197.2(201, 183, 215, 206, 181)ms - 27,004,928byte
HASH BITS 6 - 199.2(182, 220, 217, 189, 188)ms - 27,406,336byte
HASH BITS 7 - 192.4(194, 191, 184, 189, 204)ms - 28,024,832byte
推定最適値 -- 216.6(261, 195, 210, 214, 203)ms - 27,140,096byte

推定最適値は要素数をCount+(DataAreaSize-1)として求めたもの。
厳密には異なるが近い値になる。
実数はバイトコード解析しないと出せないはず。
推定最適値が遅かったので、再度 3 の時計測
HASH BITS 3 - 213.8(206, 219, 199, 212, 233)ms
似たような値になった。
実行タイミングによって少し遅くなっていたり速くなっていたりすることがあるので、測ってみたが予想通り。

平均値を見ると少し差があるが、各実行時の時間を見ると、誤差の範囲で特に速度向上は見られない。
メモリ使用量は何度か実行すると多少上下する様子。
ただ、テーブルサイズを大きくするに従って大きくなって行っているのは見て取れる。

実使用環境でもっともオブジェクトの生成を行うであろう起動時でも特に有意な差は見られない。


次に明確な差が出るであろうLayer 生成を1万回行うのに要する時間を同じように計測。

HASH BITS 3 - 532.4(530, 535, 525, 542, 530)ms
HASH BITS 4 - 525.4(516, 535, 519, 536, 521)ms
HASH BITS 5 - 482.6(483, 481, 481, 484, 484)ms
推定最適値 -- 441.0(450, 436, 443, 437, 439)ms

だいたい値が大きくなると速くなっている。
ただ、このようにひたすら生成だけをひたすら繰り返すことはほとんどない。

ハッシュテーブルからオブジェクト検索時、見付けたものをリストの先頭に置き、連続でアクセスされた時、次回から検索が即座に終わるような実装になっている。
このためいくつかのオブジェクトに集中的にアクセスするような状況では、検索時間に差は出にくくなっていると考えられる。
後はキャッシュなどでペナルティがある可能性だろうか。

ハッシュテーブルサイズの初期値を大きくしても実使用時では特に影響ない。
大量に要素数がある辞書を生成するロード時は、バイナリでの読み書きを使用すればもっとも高速化されるはずなので、初期値を変えてもあまり意味はないし、一部の要素数が特に多いオブジェクトのために初期値を変える意味は見出せない。
数万など要素数が極端に大きい辞書を扱う場合は、Dictionary のコンストラクタで要素数を指定できるようになっているので、そちらを使うのが現実的。


結果として、ハッシュテーブルサイズの初期値を変更する意味は見出せず。
Array/Dictionary の saveStruct の第2引数に "b" を入れてバイナリ形式で書き出すのと、Dictionary の要素数指定を適時使うのが効果的。

投稿者 Takenori : 05:38 | トラックバック

2013年11月26日

吉里吉里Z β5 バイナリ

krkrz_20131126.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

今回から吉里吉里デバッガが同梱されています。

投稿者 Takenori : 00:26 | トラックバック

2013年12月03日

吉里吉里Z β6 バイナリ

krkrz_20131203.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

主な変更点
System.desktop* が返す値をメインウィンドウがあるモニタの作業領域に変更しました。
System.touchDevice プロパティの追加、定数 mbX1, mbX2 の追加が行われています。
Font.getList の フラグにシンボルキャラセットを除外する fsfIgnoreSymbol を追加しました。
その他不具合修正等が行われています。

System.touchDevice は、以下のフラグの組み合わせです。
tdIntegratedTouch : 統合型のタッチ デジタイザー
tdExternalTouch : 外付けのタッチ デジタイザー
tdIntegratedPen : 統合型のペン デジタイザー
tdExternalPen : 外付けのペン デジタイザー
tdMultiInput : 複数入力(マルチタッチ)サポート
tdDigitizerReady : 入力デジタイザーで入力の準備完了
tdMouse : マウス接続
tdMouseWheel : マウスホイールサポート

定数 mbX1, mbX2 は、マウスボタン定数です。
主に5ボタンマウスの進む、戻るに割り当てられています。
実装はありましたが、定数が定義されていませんでした。

投稿者 Takenori : 04:03 | トラックバック

2013年12月10日

吉里吉里Z β7 バイナリ

krkrz_20131210.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

吉里吉里2 では例外発生時に発生箇所のスクリプトが表示されていましたが、吉里吉里Z ではダイアログのみで不便だったため、外部エディタ起動機能を追加しました。
-exceptionexe でエディタを、-exceptionarg で引数を指定し、任意のエディタで例外発生行にカーソルを置いて表示されることが出来ます。

Visual Studio では以下のように指定します。
-exceptionexe=devenv -exceptionarg="/edit %filepath% /command \"Edit.GoTo %line%\""
Visual Studio が既に起動している場合は、起動されている Visual Studio でファイルが開かれますが、その場合指定行に移動しないようです。
新規に起動された場合は移動します。

サクラエディタでは以下のように指定します。
-exceptionexe="sakura.exe" -exceptionarg="%filepath% -Y=%line%"

バッチファイルに書く場合は、% を %% とエスケープする必要があるので注意が必要です。

この機能は TVP_ENABLE_EXECUTE_AT_EXCEPTION を指定してコンパイルした場合に有効です。
配布バイナリの tvpwin32.exe では有効になっていますが、デバッガ用バイナリでは無効になっています。

TJS2 を記述していてよく発生するシンタックスエラー等の場合、エディタが開くので、すぐに修正して再度実行できるため、便利になるケースがあると思います。

Debug 版を Visual Studio でデバッグ実行する時、例外が発生すると停止するようにしています。
その時、Visual Studio のデバッグ出力にタグジャンプ用のメッセージが表示されるようにしているので、その行をダブルクリックすれば、Visual Studio でスクリプト例外発生行を開けます。


プライマリーレイヤーのサイズとクライアント領域が同じサイズとなる仕様はなくなり、別扱いとなりました。
Window のクラアント領域よりプライマリーレイヤーのサイズが小さい時は、レイヤーがない部分については黒で塗り潰されます。
逆にプライマリーレイヤーサイズが大きい場合、Window 表示では Window によってクリッピングされますが、フルスクリーン時は全体が Window 時のアスペクト比に合わせて伸縮して表示されます(この動作については修正される可能性もあります)。


その他
ブログには書いていませんでしたが、Font.doUserSelect/System.inputString は削除されています。

投稿者 Takenori : 01:05 | トラックバック

2013年12月14日

エンジン設定用リソース

吉里吉里2 では、本体は TVPGetCommandDesc で得られる "|" 区切り(他の区切り文字もあり)の文字列を得て、それを元にエンジン設定の項目を表示していた。
また、プラグインでは、コメント部に --has-option-- を入れて、GetOptionDesc 関数を公開し、その中で本体と同じ文字列フォーマットで設定の詳細を入れていた。
リンカに /COMMENT: で --has-option-- を追加していたが、最近の Visual Studio では無視されるので、通常の方法ではこれを DLL バイナリに入れることは出来ない。

吉里吉里Z では、設定項目のリストは JSON にし、ソースに埋め込むのではなくリソースに入れる方法に変更した。
JSON の具体的なフォーマットは、ファイルを見ればだいたい分かるはず。
本体の方はリソースの option_desc_ja.json を編集してもらえば反映されるのでいいとして、プラグイン側は少し注意が必要。
リソースの種類は、TEXT で、ID は文字列 IDR_OPTION_DESC_JSON で DLL に格納する。

具体的には *.rc ファイルに、以下のように記述してリソースに追加する。
IDR_OPTION_DESC_JSON TEXT "option_desc_ja.json"

resource.h では、IDR_OPTION_DESC_JSON を定義しない
IDR_OPTION_DESC_JSON を定義するとリソース ID が数値で追加される。

数値になっているか文字列になっているかは重要で、FindResource が失敗してしばらく悩んだ。
数値の場合は、MAKEINTRESOURCE(IDR_OPTION_DESC_JSON) 等としてリソースを指定するが、文字列の場合は、TEXT("IDR_OPTION_DESC_JSON") 等して文字列で検索する。
MAKEINTRESOURCE は、単純に数値をアドレスとして返しているだけで、上位 16 ビットが 0 になるかどうかで文字列か数値かを判定している模様。
数値で登録されているのに文字列で検索したり、文字列で登録されているのに数値で検索すると FindResource は失敗する。
Visual Studio 上から追加すると、resource.h に define が追加され、数値となる。
ID のところで "IDR_OPTION_DESC_JSON" と入力すると "\"IDR_OPTION_DESC_JSON\"" とダブルクォーテーション付きの ID となる。
当然、" も含んだ文字列でないと検索でヒットしなくなる。
つまり、Visual Studio 上から追加した場合は、MAKEINTRESOURCE(RESOURCE_ID) で検索されることを想定している。
数値で登録されている場合、数値を指定して検索すればヒットするので、共通の数値を使ってもいいが、文字列の方が複数 DLL で統一しやすいだろうことから文字列とした。

投稿者 Takenori : 03:38 | トラックバック

エンジン設定ツール

吉里吉里Z では、独立したエンジン設定ツールはなくなった。
本体に -userconf を指定して起動すると、ユーザー向けエンジン設定ツールとして起動する。
インストーラー等で本体の引数に -userconf を追加したショートカット等をエンジン設定ツールとして登録すれば従来と同じように扱える。

開発者用エンジン設定ツールは提供されない。
デフォルト設定は、optionarea.txt で改行区切りで引数と同じものを与えれば設定を変更できる。
ユーザー設定で表示させたくない項目を、option_desc_ja.json で "user":false とするか、項目そのものを削除してしまえば表示されない。
設定がうまく表示されない場合、ログに JSON の文法違反が出ている可能性があるので、コンソールで起動してログを見てみると良い。
これらの変更を反映するには、コアのビルドかリソースを変更できるツールで変更することが必要になる。
将来的に専用のリソース変更ツールを作る可能性はある。

投稿者 Takenori : 04:06 | トラックバック

2013年12月16日

吉里吉里Z β8 バイナリ

krkrz_20131216.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

今回からエンジン設定が追加されています。
-userconf で起動します。

投稿者 Takenori : 23:35 | トラックバック

2013年12月17日

吉里吉里Z リポジトリの移動

今まで、GitHub の jin1016 の下に krkrz リポジトリがあったが、krkrz organization (グループ) の下の krkrz に移動した。

https://github.com/krkrz/krkrz

リポジトリ移動に伴い、Issues も移動になっている。
https://github.com/krkrz/krkrz/issues

個人アカウントの下にぶら下がっているよりも、GitHub organization (GitHub グループ) の方が好ましいと思われるので移動した。
organization だと管理者メンバーを増やして管理できる。
リンクや Git の設定など変更が必要なケースがあると思うので、今後注意が必要です。

投稿者 Takenori : 01:19 | トラックバック

フレーム単位でのマルチスレッド化

以下のような書き込みを見かけて少し考えてみた。
単なる思考実験。

吉里吉里2では、描画メソッド単位でマルチスレッド化しているから、あんまり速度出ない。
そうじゃなくて、フレーム単位でマルチスレッド化すれば速度が出るはず。

見た時、そんな無茶なと思ったものの、どうすれば実現可能か考えてみた。
思い付く方法は 1つ。
Layer 構造の描画に必要な情報のスナップショットを取り、それを元に別スレッドで描画すれば良い。
Bitmap は Copy-On-Write 管理されているので、コピーも少なくて済むはず。
アニメーションやトランジションなど、スタートとゴールがわかっているのなら、その期間を適当な間隔で区切ってスナップショット作って、別スレッドでレンダリングさせていけば、フレーム単位でマルチスレッド化出来る。
ただ、その場合通常は負荷がかかった時ドロップフレームが発生する形になるのに対し、この方法では動きがゆっくりになると言う違いが出る。
スナップショットをクラスとして、好きにレンダリング要求を出して、レンダリング後の Bitmap を取り出せると汎用的に扱える。

意外となんとかなりそうか? と思ったものの問題に気付く。
ダーティー領域を考慮できなくなるので、小領域の更新の時、非効率的になる。

全体の描画で単純に描画を別スレッド化するだけなら、ダーティー領域の問題はなくなるし、入力の応答性は改善され、少し快適に動作するかもしれない。

投稿者 Takenori : 23:23 | トラックバック

2013年12月20日

Opus プラグイン

krkrz_opus.zip

Opus のテスト用サンプルです。
テスト用に作った kropus.dll を使い吉里吉里で再生することができます。
runsjis.bat で実行してみてください。

主に音声用のようですが Vorbis と比べて Opus はファイルサイズが約 1/2 となっているので、アーカイブサイズを節約できそうです。
kropus.dll はモノラル以外ではテストしていません。
また、実験的に実装したものなので、不具合がある可能性があります。

Opus (Wikipedia)

213/12/22 追記:
kropus.dll
DLL バイナリ更新。
最初にリリースしたものでは、ステレオ ( 2チャンネル以上 ) の時、正常に再生できなかったものを修正。
DLL 自体は、吉里吉里2 でも動作することを確認。

投稿者 Takenori : 01:26 | トラックバック

2013年12月24日

吉里吉里Z β9 バイナリ

krkrz_20131224.zip
既に正式版が出ているので吉里吉里Zのページからダウンロードしてください。

今回から Opusプラグインが添付されています。
その他不具合修正を行いました。

投稿者 Takenori : 02:34 | トラックバック

2013年12月31日

吉里吉里Z Ver1.0 リリース

ダウンロードは 吉里吉里Zページ から。

最初の正式バージョンです。

GitHub で リリースタグも作っています。
β版時には含まれていた KAG3 は含まれていません。
現在のところ KAG3 含めツール等は吉里吉里2に依存しています。

投稿者 Takenori : 04:09 | トラックバック

2014年01月13日

メモリ断片化低減対策

メモリの断片化によって「ビットマップ用メモリを確保できません/……」もしくは「Cannot allocate memory for Bitmap : ……」と言ったエラーが発生することに対する対策を追加した。

メモリ不足はどうしようもないが、断片化はある程度対策がとれる。
比較的大きな領域を確保するビットマップ用のメモリリージョンを別に設ければ、ある程度断片化を防げる。
Windows だとヒープを分けられるので、HeapCreate を使えば断片化が抑止出来るのではないかと考え、これを利用したメモリ確保方法を追加した(実際に効果があるかは不明)。
また、ビットマップはメモリ解放頻度が他と比べて低いと考えられるため、HeapCompact を解放するたびに呼び出す実装とした。
説明を読むと HeapCompact はメモリコンパクションと思われる。
通常、HeapCompact がどの程度の頻度で呼ばれるのかは知らないが、そう頻繁に呼ばれていないのではないかと思われる。

デフォルトは従来と同じ方法となるように bitmapallocator オプションで指定可能とした。
globalalloc を指定すれば従来と同じように GlobalAlloc が使われる。
何も指定しない場合は、これがデフォルト動作となる。
separateheap を指定した場合、上述の HeapCreate が使用されることになる。
malloc を指定した場合は、malloc で確保する。

separateheap を指定した場合、初期ヒープサイズを別に指定できる。
bitmapheapsize オプションで指定可能。
デフォルトは自動で、MEMORYSTATUSEX.ullAvailVirtual から 128MB 引いたサイズ以下で割り当て可能になるまで128MBずつ引いていくような実装になっている。
ullAvailVirtual が 512MB 以下の時は、初期では半分を割り当てようとする。
かなり大きなサイズをこのヒープに割り当てようとするので、グラフィックキャッシュの指定容量が大きいと競合するかもしれない。

「ビットマップ用メモリを確保できません」と言うエラーが出るような状況では、グラフィックキャッシュは使用しない方が好ましい。
キャッシュはメモリが余っている時にするもので、逼迫している時は使わない方が良い。
キャッシュによってメモリが解放されないと、断片化の要因ともなりうる (未開放メモリが間にあるとコンパクションで結合できない)。
断片化によるメモリ不足解消のために separateheap 指定するような状況の場合、グラフィックキャッシュは無効化するであろうことから、競合は考えなくても良いかもしれない。

上記対策に加えて LFH の有効化オプションも追加した。
XP 以降で低メモリ断片化機能 ( LFH ) が追加されているので、uselfh オプションを指定することで有効化できるようにした。
ただ、Vista 以降はデフォルトらしいので、実質的には XP でのみ意味のある機能かもしれない。
デフォルトは従来と同じになるように OFF にしてある (とは言っても、Vista 以降は有効 )。

「ビットマップ用メモリを確保できません」で検索すると何件かエラー報告が上がっているのが見付けられる。
自身の環境で発生したことはないので上記の対策がどの程度効果を発揮するかはわからないが、何もしないよりは効果があるのではないかと思う。

投稿者 Takenori : 05:41 | トラックバック

2014年01月14日

グローバルヒープもHeapCompact可能に

-ghcompact オプションで、グローバルヒープも HeapCompact 可能にした。
実行されるのは、System.doCompact が clAll 指定で呼ばれた時。
LFH が有効な時は、doCompact タイミングで HeapCompact 実行しても効果は薄い様子。
Bitmap 用の separateheap で Free されるたびに HeapCompact しているのはかなり効果的な模様。
だから、-ghcompact を指定する意味はあまりないかもしれない。

後、System.dumpHeap() を追加した。
呼ぶとログにヒープの使用状況がダンプされる。

separateheap で初期サイズを自動とした時、上限を 512MB とするようにした。
1GB 以上も割り当てるのはさすが好ましくないという判断。
初期サイズなので、足りなくなったら拡張される。

ヒープのダンプを見ると、separateheap はかなり良好に働いているように見える。
これで Bitmap メモリの断片化によるメモリ確保の失敗は軽減できそう。
実使用環境でエージングしてみないと効果のほどは不明ではあるけど。

投稿者 Takenori : 01:45 | トラックバック

2014年01月17日

画面の回転イベント

画面の回転イベントを追加した。

Window.onDisplayRotate(orientation, angle, bpp, width, height)

向き ( orientation ) は、以下のいずれか。
oriUnknown (取得失敗/不明), oriPortrait(縦向き), oriLandscape(横向き)

角度 ( angle ) は、0、90、180、270、-1 のいずれかで、取得できなかった時は-1となる。
角度は、そのデバイスデフォルトからの回転角なので、縦向きのデバイスでは縦向きで0となる。
通常のデバイスだと、横向きで0が多い。
縦向きが0になるのは最近の8インチタブレットなどで、縦向きが標準の向きとなっているもの。

bpp は bits per pixel で、width / height は画面の幅と高さ。

イベント以外に、プロパティでも取得できるようにした。
それぞれ以下のプロパティで取得できる。

Window.displayOrientation
Window.displayRotate

OnDisplayRotate は、DrawDevice にもメソッドを追加したので、DrawDevice プラグインの変更も必要。
ただし、現在デフォルトでは OnDisplayRotate イベントが発生しても何もしないので、特に必要なければ実装の必要がない。
プラグイン用のベースクラスは何もしない形で実装済みなので、ベースクラスを継承して作っている場合はリビルドのみ必要。
フルスクリーン時の画面回転についてテストが漏れていたので、何か不具合があるかもしれないため、その対応で OnDisplayRotate イベントで何かしら処理を追加する可能性はある。

投稿者 Takenori : 03:55 | トラックバック

2014年01月20日

吉里吉里2 VC対応(吉里吉里Z) に出資する場合の疑問点

意図とは違う部分があったようなので、冒頭部分の修正とQ&Aを一つ追加しました。
最初の冒頭文章は頭に血が上って少し攻撃的になっていたこと、お詫びします。

指摘は1月18日にあり、内容を要約すると以下の通りです。
・吉里吉里への寄付を集めているのか、VC対応するから開発費下さいと言っているのか、その辺りがわかりづらいので、怪しい広告に見える。
・出資する側からしたら、何にお金を出すのか、お金を出すメリットは何なのか、余ったお金はどうなるのかがわかりづらいので、説明しておいた方が良い。


Q. なんでお金集めてるの?

吉里吉里2をVCでビルドできるようにしたいからです。


Q. 開発費はなんで必要なの?

A. 残念ながらプログラムはどこからともなく降って湧いてくるわけではなく、人が書いて作っています。
人が作る以上人件費が発生します。
つまり、そのコストを誰かが負担する必要があります。
だから、開発費は必要です。


Q. 200万ないと開発できないの?

A. 私にはないと出来ません。
私の工数見積もりでは、4ヶ月は必要でした。
もっと早く完成させられる人であれば、もう少しコストを抑えられるかもしれません。
工数云々ではなく、お金が必要なのか?と言う意味であれば、先の回答と重複しますが、必要です。
フリーソフトとかただじゃないかと思うかもしれませんが、それは利用者から見たら無料に見えるだけであって、開発費は0円ではありません。
そのコストは開発者が負担しているだけです。
他の人に200万円負担してもらうか、自分で200万円負担するかの違いです。


Q. 200万は何に使ったの?

人件費です。
最終的には約450万円開発にかかりました。
クラウドファンディングで306万円集まったので、結果306-450=-144万円です。
306万円のうち、自分の分が50万円分含まれていたので、194万円分自身で負担しました。


Q. クラウドファンディングって何?

A. 検索して調べてください。


Q. お金出して何のメリットがあるの?

A. 吉里吉里2 が VC でビルドできるようになります(なりました)。
また、いくつかの機能追加も行われました。
お金を出す、出さないに関わらず修正BSDライセンスに従えば誰でも利用可能です。
誰でも利用可能なので、お金を出した人はコントリビューターの項に名前が載るのみで、出す出さないの差は言えばそこだけです。
それだとお金出すメリットはないと考える人であれば、メリットはありません。
自分ではなく他の誰かがやってくれるまで待つか、自分で前に進めようとするか、前に進めようとしている人を支援するかの違いです。
待っているだけでは、永遠に完成しないかもしれないし、その内完成するかもしれません。
自分でやったり、支援すれば完成する可能性が高くなります。
その辺りもメリットと言えますが、結局は思想やスタンスの問題でしかないかもしれません。


Q. 寄付じゃないの?

A. 「パトロン → 私へ開発委託 → オープンソースで公開」の最初と最後の関係で言えばプロジェクトへの寄付ですが、直接的な部分は開発の委託です。


Q. 余剰金はどうするの?

A. 機能追加に回します。
吉里吉里2VC対応追加項目希望アンケート にて募集しました。
200万円を超えることを意識していませんでしたので、後からの補足となりました。

投稿者 Takenori : 00:23 | トラックバック

いろいろと見積もってみる

64bit化 - 工数を見積もるのに 1、2人日かかりそう。
ほとんどはアセンブリからイントリンシックを使ってCに書き換える作業になるので、いくつかやってみて、分量から工数を割り出す必要がある。
実作業はまずはブランチ or フォーク。
マージ時は手動マージが必要と考えられるので、完全に分岐して、最後にメインに手動で統合する方が楽そう。
統合時は64bitの方をメインとした方が楽かもしれない。

1. nasmソースは除いて、C言語版のみ使用しビルドが通るようにする。
2. SIMD 版スタブを作り、中身はC言語版を呼び出すようにする。
この2つの作業のみであれば、順調に行った場合 2日程度で行けるのではないかと思われる(吉里吉里Z実装時、ある程度64bit化を見越した対応を行っているが、ビルドや動作確認は行っていないため不具合に出くわす可能性がある)。
あとは、ひたすらアセンブリからC言語へ書き換えていく作業になる。
この書き換え作業は、人海戦術や少しずつの時間の積み重ねで行いやすいので、このような方法でやっていけば実現しやすい。
64bit 版になるとメモリ使用可能量は増加するものの、高速化についてはケースバイケース。
遅くなることもある。
やるのなら SSE2 のサポートも行うことになるだろうから、SSE2 が速い CPU であれば、その部分で高速化出来る可能性がある。


新KAG開発 2人月~
どの程度の機能を入れるかによって増減する。
他の機能との兼ね合いもある。


Visual Studio での TJS2 スクリプトとデバッグのサポート 1人月~
TJS2 の構文解析など必要となるので、TJS2 言語拡張等と共通する作業がある。


アニメーションツール開発と再生のサポート 1人月~
最低限の機能であれば1人月程度で実装可能だが、様々な機能が欲しくなるだろうから、実際はここからさらにかかることになると思う。


新KAGでの開発支援環境の開発 1人月~
支援環境を実現しやすいように新KAGがデザインされていた場合、1人月程度で出来ると考えられるが、何も考えられていない場合は工数は伸びる。
また追加する機能によっても工数は増加する。


マルチプラットフォーム化
必要な作業は以下。
1.Window等の環境・GUI依存部分(イベント、スレッドなど含む)。- 環境ごとに必要、1、2人月
2.サウンド OpenAL である程度共通化できる。Android であれば OpenSL 。- それぞれ 10人日程度。
3.動画 モバイル端末であれば組み込み機能、その他であれば独自の再生エンジンで共通化できる。 - 3人月程度
4.プラグイン DLL/Shared Library を環境に合わせて実装する必要がある。 - 1人月
5.DrawDevice部分 OpenGL化 Windows以外では、最終段階は OpenGLで描画で共通化できる。 - 10人日程度
以下の4つプラットフォームに対応するとするのなら上記合計すると13.5人月程度。
・MAC OSX
・Linux
・iPhone
・Android
羽々斬や吉里吉里Zを実装した経験から言うのなら、PC系OS以外へは別のアプローチをとるべき。
新KAGを実現できるように実装した方が良い。
また、新KAGのデザインもそれを考慮されたものになっている方が良い。


TJS2言語拡張 3人月~
・コンパイル部分の整理
・foreach 組み込み
・型指定
・型推論
・コルーチン
・Rubyのブロックの様な機能・構文
・メンバ存在チェック機構
・JIT(LLVM)対応
・(パッケージ機構)
・(シリアライズ機能)


Layer.operateAffine で引数 mode 指定時の未実装機能
補間方法ではなく演算方法のサポートとして 10人日程度か。実際には単純作業なので、いくつかやってみてから見積もらないと正確には出しづらい。


画面回転ロック
現状実現方法がわからないので何とも言えない。わかりさえすれば1人日。


ペン入力対応 - 10人日


フリック等ジェスチャー系の入力補助 - 何をサポートするかによる。調整期間を考えなければ5人日程度か。


Ogg Vorbis を高速化プロジェクトのものへ置き換え - Opus があるので対応自体必要か微妙。


バイナリファイル読込み機能(binaryStreamプラグインのような機能内包) - 2人日


ゲーム用UIシステム 1人月~
GUIデザインツールなど考えるともう少し増加する可能性も。


GPU 処理対応 2人月~
CPU処理が吉里吉里の利点でもあるが、高解像度化によってCPU処理では厳しい場面も出てきていることを考えると将来的には必要になる。
また、モバイルプラットフォーム等を考えるのであれば、GPU で可能(効率的)な処理とすることは意味がある。


見積もりに時間がかかる64bit化を除いて、もし上記全てやるとしたら26人月程度。
1人月50万円なら1300万円必要。
上記は概算なので、実際にはより精度を上げて見積もるだろうし、安全率をかけるだろうから、倍額程度か。

1,2人日程度の作業であれば、合間に作業することで実現可能であるが、5人日を超える様なものについては、実際に仕事として発生しないと実現の可能性は低くなる。
どうしても欲しくて、モチベーションを高く保てるものであれば出来なくはないが……
これらはあくまで自分がやるとしたら~と言う話。

投稿者 Takenori : 03:05 | トラックバック

2014年01月27日

Window 抽象化機構

Window 抽象化機構の組み込みを検討している。
現在、プライマリレイヤーを生成する時、必ず Window オブジェクトを指定しなければならないようになっている。
これを Graphics Interface (仮) を持つオブジェクトであれば許容する構造にする。

Bitmap クラスを追加したので、ツール用途で Layer 単体で Window を生成せずに利用したいケースは減ったかもしれないが、これを Graphics Interface をもつほぼ何もしないオブジェクトを渡して、Window を作らずに Layer 処理できるように出来る。
また、何もしないのではなく、最終描画を Window ではなく、Bitmap に行うクラスを作り、描画更新があればイベントで通知される形であれば、レイヤーを更新しながら、更新通知を受けて Bitmap を順次保存していくことで動画を作ったりできる。

Window を持たないデバイスや環境への対応準備でもある。
タブレット/スマフォ、Windows ストアアプリ等、全画面利用が前提で Window がない環境では、Window クラスは足かせである。
この機構があれば、Graphics Interface を持つ任意クラスを作り、Window なしで動作させられる。
Window クラスがなければ、Window のインターフェイスのスタブ等を実装しなくて良くなる。
また、Window がないのに Window を生成したり、常にフルスクリーンなのに指定したり判定すると言った不自然な仕様をなくせる。
当然、対応させる場合には Window に依存したスクリプトは変更の必要が出るが。

ハードウェア描画対応の準備も兼ねている。
最初に Bitmap クラスに描画するクラス例を書いたが、それを Texture にして描画すれば、ハードウェア描画でビルボードの一部を従来のレイヤー機構を使って描画すると言ったことも可能になる。

Graphics Interface は、Layer や LayerManger から要求で、以下の機能が必要になる。
・描画処理
・マウスカーソル/キャプチャ解放処理
・ヒント設定処理
・サイズ変更通知
・文字入力/IME 制御
表示装置側から LayerManger への通知等で以下の機能が必要になる。
・Layer 等からの描画更新要求の中継
・システムからの再描画要求
・マウス入力の通知
・タッチ入力の通知
・キーボード入力の通知
・画面回転の通知

これら Graphics Interface が必要とする機能を実装すれば、レイヤー機構を使う様々な機能を組み込み可能となる。
ネットワーク越しに操作する等もやろうと思えば出来る。
必要とされる要件が分かりやすくなるので、移植なども行いやすくなる。
当然のことながら、従来の Window を Layer に指定して、描画する機能はそのまま利用できる。

Graphics Interface と言う名前は、いい名前が思い浮かばなかったのでとりあえず付けた。

投稿者 Takenori : 02:36 | トラックバック

2014年01月29日

Layer Tree Owner

Window 抽象化機構 として、前回書いたものです。
より分かりやすい名前ということで、Layer Tree Owner としました。
今まで Layer は必ず Window が保有し、Window オブジェクトを指定しないと、Layer クラスを生成できなかったものを、Layer Tree Owner Intarface を実装するクラスであれば、Layer を保有できるような構造を入れました。
iTVPLayerTreeOwner を実装し、layerTreeOwnerInterface プロパティでそのインターフェイスのポインタを返すことで、Layer Tree Owner となります。
LayerManager/Layer から呼び出されるメソッドの実装は必須ですが、LayerManager へイベントを伝えるメソッドの実装は自由になっています。
まずは、Layer Tree Owner Intarface を実装したクラスとして、Window 以外に BitmapLayerTreeOwner クラスを追加しました。
BitmapLayerTreeOwner は、描画を Bitmap に行うクラスです。
そのままでは画面などには描画されないので、画面に描画したい時は画像更新イベントを受けたら Layer にコピーするなどする必要があります。
ただ、性質上ツールなど用で Window ではなくファイルに保存するなどしたい場合に使えると思います。
BitmapLayerTreeOwner は以下のメソッドを実装しています。

class BitmapLayerTreeOwner {
// functions
function BitmapLayerTreeOwner()
function fireClick( x, y )
function fireDoubleClick( x, y )
function fireMouseDown( x, y, mb, flags )
function fireMouseUp( x, y, mb, flags )
function fireMouseMove( x, y, flags )
function fireMouseWheel( shift, delta, x, y )
function fireReleaseCapture()
function fireMouseOutOfWindow()
function fireTouchDown( x, y, cx, cy, id )
function fireTouchUp( x, y, cx, cy, id )
function fireTouchMove( x, y, cx, cy, id )
function fireTouchScaling( startdist, curdist, cx, cy, flag )
function fireTouchRotate( startangle, curangle, dist, cx, cy, flag )
function fireMultiTouch()
function fireKeyDown( key, shift )
function fireKeyUp( key, shift )
function fireKeyPress( key)
function fireDisplayRotate( orientation, rotate, bpp, hresolution, vresolution )
function fireRecheckInputState()

// events
function onSetMouseCursor( cursor )
function onGetCursorPos( x, y )
function onSetCursorPos( x, y )
function onReleaseMouseCapture()
function onSetHintText( sender, hint )
function onResizeLayer( w, h )
function onChangeLayerImage()
function onSetAttentionPoint( layer, x, y )
function onDisableAttentionPoint()
function onSetImeMode( mode )
function onResetImeMode()

// properties
property width r
property height r
property bitmap r
property layerTreeOwnerInterface r for internal
property focusedLayer
property primaryLayer r
}

通常とメソッド/イベントが逆になっていることに注意。
LayerManager から呼ばれるものが on~とイベントになっていて、LayerManager へイベントで通知するものがfire~となっている。

現在のところ、この機能は dev_layer_tree_owner ブランチに入れています。

このインターフェイスで、複数のプライマリーレイヤーをより自然な形で実装しやすくなります。
今までは、1つの DrawDevice に複数の LayerManager がつながる形で少しやっかいでしたが、Layer Tree Owner では、DrawDevice に任意ノードを追加し、そのノードを Layer Tree Owner とすることで、複数のレイヤーツリーをノードに分離して、管理できます。
BitmapLayerTreeOwner 以外に、複数のレイヤーツリーを作ることの出来る DrawDevice は実装予定です。

投稿者 Takenori : 23:06 | トラックバック

Extension

Plugin は、実行時にクラスやメソッドを追加する機能ですが、ビルド時にクラス等を追加する機能を検討しています。

static tTVPAtInstallClass TVPInstallClassFoo(TJS_W("ClassFoo"), TVPCreateNativeClass_ClassFoo);

このような形で cpp に記述し、リンクするとデフォルトクラス追加後に、順次追加される形です。
これがあると本体に組み込むクラスを取捨選択出来るようになります。
依存関係のあるクラスは難しいですが、独立しているものであれば、任意の組み合わせで欲しいクラスのみを持ったコアを作れるように出来ます。

投稿者 Takenori : 23:54 | トラックバック

2014年02月02日

吉里吉里Z 関東打ち上げに行ってきた

プロジェクト開始した頃に打ち上げの話があって、それはいい、やろうと言うことで開催。
感想を一言で言うなら、「やって良かった」。
課題や問題点などいくつか理解できたし、人となりは実際に会ってもやっぱりネットとあんまり変わらないなって感じだった。
でも、実際に会って話せると得るものは大きい。
席の関係で初めての人とはほとんど話せなかったけども。

打ち上げの時と言うか、その前から Android版作りたいなぁって感じだったけど、やっぱり吉里吉里Z Android版作ろう。
当たり前だけど、PC版と完全互換にはならない。
スクリプトレベルで互換をとることは可能だけど。

まずは、制限や見積もりをまとめよう。

投稿者 Takenori : 15:43 | トラックバック

TJS2 型指定可能について考えてみる

1. 単純に構文として受け入れるだけ。
bisonスクリプト10行くらい書き換えれば対応できるかな。

2. コンパイル時にエラーが出る。
そこそこ修正範囲広くなるけど、1日もかからない対応。テストはもう少しかかる。

3. VMでの型情報対応。
これは工数かかる。


1 は、ほとんど意味がないけど、スクリプトの見た目上対応しているように見える。
気分的にうれしいくらいで、他に意味はない。
2 は、エラーを減らせるのでうれしいが、コンパイルが実行時に行われる関係で実行してみないとわからないのが難点。
バイトコードへのコンパイルをチェックのために走らせるよう習慣づければ、事前にわかるのでうれしい。
エディタで対応し、コーディング中にコンパイルエラーが出ればかなり効率的。
3 は、大変だけど実行時の効率にも影響してくるので、かなりありがたい。
JIT まで出来れぱ、型情報があると演算のみならネイティブ並の速度。
ただ、プロパティアクセスや関数呼び出しは、動的言語なのでかなり重い処理となってしまうのは変わらず。

関数の引数や戻り値、プロパティの値などは、型を指定したとしても、内部的にはバリアント型となるかな。
内部的に型があっても、どのオブジェクトの関数やプロパティかは実行時までわからないので、実行時例外となってしまう。
呼び出し前に型チェックして、関数内ではその型とみなして処理すると効率は上がる。
引数を関数内で利用している箇所の型を明示できるし、返り値についても同様なので、そこのメリットもある。
プロパティもその内部で処理している範囲なら意味がある。
関数よりは遥かに意味が薄いけど。

追記:
var hoge:Layer; とか指定できれば、 エディタでインテリセンスが使えるとレスをもらった。
それは確かにいいな。
基本ActionScript合わせにするつもりだけど、仕様の検討と調査してみよう。

投稿者 Takenori : 17:16 | トラックバック

TJS2 型指定可能版

文法は、以下のように ActionScript とだいたい合わせた。
var hoge:Layer;
var hoge:Layer = new Layer(...);
function foo(hoge:Layer):Layer { return hoge; }
property hoge {
setter(arg:int){}
getter():int{ return a; }
}

property の指定は、次の文法と迷うところだけと、とりあえず上述のようにしておいた。
変えてしまう可能性もある。

property hoge : int {
setter(arg){}
getter(){ return a; }
}

var host:*; などは対応していない

型の種類は次の通り
オブジェクト型(クラス名)
void
int
real
string
octet

boolean と number は対応していないと言うか、内部的にないので。
ただ、boolean ないと少し不便なので、内部的には int として追加する可能性も。
インライン Dictionary での型指定も対応していない。

文法を許容するだけで、それ以外は全く何もしていない。
コンパイルエラーなどでないし、内部で速くなるとかは何もない。
将来的に対応できたらいいねと言うことで。
型を指定して TJS2 で書いてみると、安心感と可読性が上がるので、文法だけサポートしているのも意味がありそう。
インテリセンスなくても。

バイナリはこの辺りに
後、GitHub には、dev_typed_tjs2 ブランチで入れた。

投稿者 Takenori : 21:52 | トラックバック

2014年02月03日

スレへの返答を書いておく

吉里吉里スレ27で吉里吉里Zについて疑問や質問があるみたいなので、返答しておく。


903
言っている内容は「私は吉里吉里Z(吉里吉里2VCビルド対応)にお金出していないし、要望も出していないけど、私の思っていたものとは違う。完成した後に要望出した人には開発費出したらやるって返事していた」ってことなんだけど、何一つ共感できる要素がないというか、知らんがなとしか言えないんだけども。※内容は私の解釈による要約です。
少なくとも要望があるのなら開発中に言ってくれないと、エスパーじゃないからわからないんだが……
後、吉里吉里2VCビルド対応ではKAG3は範囲外だと明言していたしなぁ。

「KAG欲しいって声には金出せばやるよって返事」
これはどのやりとりかなぁと思ってツイッターのログ見てみた。
Q.「やはり新しいKAGが欲しいです。開発費はいくらぐらいかかりますか?」
A.「100~150万くらいですかね。」
開発費いくらかかりますかと聞かれて金額を答えてた。

「吉里吉里はKAGとセットだと思ってた」
そう思っている人がどれくらいいるのかはわからないけど、少なくとも私は別と思ってますね。

「β版まではつけてたKAGを問題出たし納期あるからやっぱやめたわ吉里吉里は作ったからいいよな的な対応はどうなんだ。 」
妄想激しいな。
KAG3は範囲外だと最初に言った通り、KAG3側の対応する気はゼロだったから入ってない。
β版には確認しやすいように付けていた。

リリーサーは、吉里吉里2 のが使えるけど。

TJS2使えないんだったら、吉里吉里Zを使うメリットほぼないのに、なぜ使いたいのかと言う根本的な疑問が……

吉里吉里2の親切さに慣れて、吉里吉里Zの初期バージョンに不満爆発したのかな?
吉里吉里2のレベルに到達するには、まだまだ時間が必要だから気長に待った方が気が収まると思う。
早く何とかして欲しいということなら、自分で開発するか、お金出して仕事として開発依頼するしかない。
余暇に気ままにやっている人に期待してもどうにもならん。
KAG周りは何とかしたいとは思っているから、その内なんとかなるかも。
早く欲しいのなら、お金出して仕事として自分か誰かかに開発依頼してね。


961
なぜキレたのか知らない人にキレたことにダメ出しされてる……
確かにキレるのは良くないと思うけど、私も人間だから腹立つこともある。
腹が立ったのは言われた内容ではなく言い方の問題かな(初めから喧嘩腰で言われたように私は感じたので)。
だから指摘は的外れ。
わかっている人だけ相手にしたいのなら、IRCとかでやってる。
クラウドファンディングでお金を出す時に来た質問は答えている。
終わって、完成後にVC対応クラウドファンディングについての質問に答える意味はない(双方納得して契約して開発して終了したことだから)と思うけども、一応答えている。
黙っていてもわかる人だけ相手にしたいのなら、質問は一切無視すると思うけど……

クラウドファンディングは、吉里吉里2のVCビルドを実現するための方法を考えていた結果出した方法で、もっと良い実現可能な方法を思い付いていたのなら、それを使っている。
吉里吉里Zの開発を進めるために必要な金銭的な問題を解決する良い方法があるのなら教えて欲しい。
この問題についてはずっと考えている。

「この吉里吉里っていうソフトウェアはどの方向を見て進めてるの?」
吉里吉里/2/3はdeeさんが考えていることだからわからないけど、吉里吉里Zは、自分の思い描くゴールに向かって開発進めている。
自分の方向いていないよ!って、思うのなら、それは当たり前、私は私の先を見て開発している。
自分のために開発している。
貴重な時間を出すのだから当たり前だと思うけど。
当たり前だけどクラウドファンディングでお金出してくれた人の方向は見ている。
お金出してもらって仕事としてやったのだから、そこは当然か。
後、要望を直接くれない人の方向は向けないと言うか、要望に答えようがない。
直接ではなく、ツイッターでも2chでもなんとなく書いたつぶやきに返事して、不具合や要望に答えようとしても、途中で相手のレスが消えるので、直接言ってこない人の話に対応するのは時間の無駄と悟った。
本気で何とかして欲しいと思っているのではなく、ただ何となく言っていると思うので、面倒になると対応するの止めてしまうだと思う。
その気持ちもわかるから、不具合や要望に答えようとするのは直接言ってくれる人からかな。
方向性が全然違う要望は無理だけど。

吉里吉里Zは他にみんなが開発しやすいようにと言うのも意識している。
ここで言う吉里吉里Zはコアの話ね。
吉里吉里Zは、吉里吉里2と比較してだいぶ開発しやすくなったと思う。
ビルド周りの問題は、C++Builder2007/2006対応とだいぶ昔から取り組んでいる課題。
今回でほぼ解決できてすっきりできた。

「お前は何者なのよ?」
これは私が何者なのか?って質問?
これだけブログを長い事書いてるのに他に何が必要なのかちょっとわからないんだけども。
年齢や職業、生まれや家族構成などお見合いするのか?って、内容が必要なのかな?
吉里吉里2のVC対応するのに十分な情報はこのブログにあると思うんだけども。

「つか今知ったけど吉里吉里Z打ち上げてw 」
アホでしょ私。
自分でも吉里吉里Z打ち上げてwって思う。
結果、自分的には成果があったのでやって良かったけど。

特に私がおかしいって話だけど、おかしくなかったら吉里吉里のVC対応とかやってないな。

投稿者 Takenori : 03:45 | トラックバック

2014年02月09日

型指定対応 TJS2

dev_typed_tjs2 ブランチをマージした。
次のバージョンから TJS2 型指定可能版 で書いたような形で型を指定した TJS2 スクリプトが記述可能になる。
型を指定できるだけで、それ以外の効果はない最小対応。
記述できるけど、効果はないという点で const と同じようなもの。

型を指定できるメリットは、大きく分けると開発効率と実行効率の向上。
開発効率は、実行前にある程度問題を排除できること、エディタの支援機能が利用できることなど。
実行効率は、毎回型を見て演算する必要がなくなるので少し速くなる。
型が欲しいと言うのは、開発効率向上がメイン。

前も書いたけど対応工程を考えると以下の3つ。
1. 型指定文法を受け入れる。
2. コンパイル時にエラーが出る。
3. 型を使用したバイトコードを生成し実行する。
( + JITでネイティブに型を使用して演算できる )

今回対応したのは 1 だけ。
今までコメントで型を書いていた場合は、スクリプトにそのまま記述できるようになったので、見た目が良くなるのと将来的にコンパイル時に不具合が弾かれるようになる。
また、エディタで型情報を拾ってインテリセンスが働く場合、入力が楽になる。
( 直接確認はしてないが KKEF でクラス型を指定するとメンバがインテリセンスで入力できるようになるという情報あり )
メリットはこれくらいだけど、将来的にコンパイル時に弾けることを期待して書いておいてもいいかも。

2、3 については変更が大きく、テストが大変なのと少し心配が残るので、やるのなら一気にやってしまいたいところ。
コンパイル時のチェックだけであれば、本体でやる必要はなく、lint のようなツールを作成して弾く形の方が懸念は少ない。
ツールがバグっていてもスクリプトの確認が多めに発生する程度で、実行時にまで影響は波及しない。
ツールとして独立して作っておいて、ある程度検証できた段階で本体のコンパイル部分を一気に置き換えることが可能。
コメントからのドキュメント生成など他用途に流用しやすく作れる。
このような理由からコンパイルチェックは別ツールとして作ることを検討している。

投稿者 Takenori : 17:41 | トラックバック

2014年02月16日

吉里吉里の何がいいのか?

1. 実行ファイル単体で起動できる(インストール不要)。
2. スクリプトでWindowが作れ、GUIアプリ作りやすい。
3. API リファレンスがきちんと書かれている。
4. オープンソース&プラグイン等で拡張できる。
5. アーカイブ化して配布しやすい。
6. ノベル用システムのKAG3が一応ある。


1. インストール不要というのは楽。
使おうとしたらインストールしたり環境変数設定したりと言う手間がないし、アンインストールも考えなくていい。
実行ファイル置いて、dataフォルダ作って、startup.tjs でスクリプトを書き始めればそれで動く。

2. デフォルトでGUIアプリをごりごりスクリプトで書けると言うのは少ない。
これ単体では他のスクリプトと差が出づらいが他の要素と合わさって良さが出ていると思う。

3. リファレンスがきちんと書かれているのは重要。
マニュアルはソースコードだとさすがに心が折れる。
ドキュメントの整備は継続していく必要があると思う。

4. 拡張がしやすいのとオープンソースで困ったらソースコードが参照できるのは強い。
吉里吉里Z では本体のビルドも行いやすくなったので、プラグインのみではなく本体側も強化しやすくなった。
ただ、本体に手を入れるとマージの問題が出る。
Pull Requestして取り込まれれば気にしなくて良くなるが、公開したくない部分などもあると思う。
追加しようとしている本体でクラスを追加しやすい仕組み Extension(仮) は static library をリンクすればクラスが生えるようにできるはずなので、本体強化しやすくなるはず。

5. スクリプトをそのまま配布するのではなく、アーカイブ化して本体と共に配布できると配布しやすい。
スクリプトのままだと内部用以外は使いづらいが、アーカイブ化して本体と一緒に配布できると一般公開しやすい。

6. 現在では面倒なスクリプトのKAG3だけど、一応ノベルシステムがあるのは楽にノベルを作れるので良い。
KAG3が機能むき出しのスクリプトなのも、機能追加時にそのままその機能をタグで追加しやすいというメリットでもある。
ただ、一般向けにもそれというのは厳しい面もある。
誰か KAG4 作らないかなぁと常々思うところ。


後、プラグインが豊富と言うのもあるけど、これは 3 番のAPIリファレンスがきちんと書かれているが満たせておらず、探しづらいし使いづらいと言うのが難点で、メリットが相殺されている感がある。
プラグインのリファレンスは何とかしたいとずっと思っている。
manual.tjs から自動生成が出来るようにしたい。
この部分が解消されれば、使いやすさはさらに増すはず。
配布物にリポジトリにあるプラグインは同梱してあるとさらに良い。


欲しい機能を追加していっているが、メリットである部分を再考して、その部分をなくさず強化することでさらに使いやすさは増すはずなので、改めて考えてみた。
追加したいと思っているいくつかは、上述したメリットを強化するものであるので、早く追加したいところ。

特色の一つ CPU でレンダリングしているは、互換性の問題が出づらいと言うメリットを補強するものだけど、互換性の問題が出づらければ、CPU レンダリングでなくても良い。
可能かどうかは別にして。
後、これは実装の問題であって、内部がどうなっていても 機能として同じであれば CPU レンダリングは必須ではない。
メリットではあるものの、解像度が上がっている現状 CPU レンダリングが足を引っ張っている部分もあるので、難しい部分ではある。

投稿者 Takenori : 19:06 | トラックバック

マウスとタッチ速度計測

dev_velocity_tracking ブランチにマウスとタッチ速度計測機能を入れた。
まだテスト中。

フリックイベントなどを追加するのではなく、速度が得られる形での実装。
フリックは、タッチが離された時に速度が一定以上ならフリック、つまり velocity > X で判定可能。
慣性スクロールは、タッチが離された時の速度でスクロール維持し、次第に減速する形で実装可能。
そのほか速度が得られると何かと便利な場面がある。
単純にフリックイベントを実装するよりも使いやすいはず。

メソッドは Window.getMouseVelocity/Window.getTouchVelocity での速度取得と Window.resetMouseVelocity でのマウス計測リセット。
マウスは、ウィンドウ内に入った時から速度計測しているので、任意タイミングから測りたい場合にリセットメソッドがある。
タッチは押されてから、離されるまでの間で計測するのでリセットはない。
タッチの場合は、一連のタッチの ID を指定して取得するので、タッチが離されたイベントのメソッド呼び出しが終了すると消えてしまうので注意が必要。
取得可能になるのも ID が確定する押されてから。
速度は pixel / sec 。

タッチのみでもいいが、マウスもついでに入れた。
球を投げると言った動作をマウスでするなど出来る。

速度計測と言っても、普段は押下された位置と時間を記録しているだけで、取得のタイミングで速度計算しているので、普段の負荷は小さい。
ログはリングバッファなので、一定間隔以上は記録されない。
計算アルゴリズムは Android にあるものの1つでソースコードを持ってきて、吉里吉里Zに合う用に書き換えたもの。

投稿者 Takenori : 20:21 | トラックバック

2014年02月18日

OS機能を利用してH.264を再生する場合のライセンスを確認する

Windows 7 以降は H.264 デコーダーを持っていて、Media Foundation を使えば H.264 動画が再生可能になっている。
そこで、H.264 動画を持って OS 機能を利用して再生するゲームを配布する場合のライセンスはどのようになるのか確認した。

Windows 7 のライセンス文は以下のようになっている。

18. H.264/AVC 規格、VC-1 規格、MPEG-4 規格、および MPEG-2 規格に関する注意 本ソフトウ ェアには、H.264/AVC、VC-1、MPEG-4 Part 2、および MPEG-2 画像圧縮テクノロジが含まれます。 このテクノロジについては、MPEG LA, L.L.C. により以下の注意書きを表示することが義務付けられ ています。
本製品は、消費者による個人使用および非商業的使用を前提とし、「AVC PATENT PORTFOLIO LICENSE」、「VC-1 PATENT PORTFOLIO LICENSE」、「MPEG-4 PART 2 VISUAL PATENT PORTFOLIO LICENSE」、「MPEG-2 VIDEO PATENT PORTFOLIO LICENSE」に基づいて次の用途に限ってライセン スされています。(i) 上記の規格 (以下「ビデオ規格」といいます) に従ってビデオをエンコードする こと、または (ii) 個人使用および非商業的活動に従事する消費者がエンコードした AVC、VC-1、 MPEG-4 PART 2、および MPEG-2 ビデオをデコードする、もしくは、かかるビデオを提供するライ センスを有するビデオ プロバイダーから取得したビデオをデコードすること。本ライセンスは、本製品と共に単一の製品に含まれているかどうかにかかわらず、他の製品に適用されることはありませ ん。その他の用途については、明示か黙示かを問わず、いかなるライセンスも許諾されません。詳細情報については、MPEG LA, L.L.C. から入手できます。WWW.MPEGLA.COM をご参照ください。

これを見ると商用で利用するのは無理なようにも受け取れるが、はっきりとはどうなのかわからない。
そこで、MPEG LA に問い合わせた。
以下は、あくまで私の解釈によるものなので、実際の判断は個々で行う必要がある。
以下の解釈について私は私の行うこと以外には責任を持たない。
内容を読むと、Media Foundation を使って H.264 動画も再生可能な吉里吉里Z用プラグインを配布するのは特に問題ない様子。
問題は利用するゲーム側。
動画がトータル12分を超える場合は、当然ロイヤリティーが発生する。
トータルなので、OP、ED、カットインなどで利用すると超えてしまう可能性があるので注意。
超えた場合はロイヤリティーが発生。
12分未満の場合は、内包している動画をデコードするためのデコーダーを搭載している場合、それについてロイヤリティーが発生する。
デコーダーとは、H.264 をデコードするだけの機能を持ったもの。
だから、OS のコデックを使うのなら、ここには該当しないものと思われるが、この辺りは原文を読んでもらうとわかるが、判断しづらい部分でもある。
詳細は以下の質問の原文を確認したり、実際に問い合わせて確認する必要がある。

後、販売されている H.264 エンコーダーは、商用利用可能なものと個人用のものがあるので、動画をエンコードする時も注意する必要がある。
また、ライセンスは時々変更されるので、使用する時に変わっている可能性があるから注意する必要がある。

MPEG LA の日本語窓口に問い合わせると、英訳されて海外のライセンス窓口に行って、そこから返事が返ってきた。
だから、後半は英語になっている。
挨拶などは省いている。


OS機能を利用してH.264を再生する場合のライセンスに関して質問があります。

1.
OS機能を利用してH.264を再生するゲームエンジンを配布した場合、デコーダーのライセンスが必要になるのでしょうか?
具体的には、Window7 以降で Media Foundation を使用して動画再生可能なゲームエンジンを配布する場合です。
ゲームエンジンなので、H.264再生機能を使用したゲームを配布するかどうかは利用者次第になります。
デコーダーのライセンスが必要な場合、入力動画ファイルをチェックしてH.264動画の場合再生できないようにすれば、H.264 デコーダーとはみなされなくなるでしょうか?

2.
上記 1 のH.264が再生可能なゲームエンジンを使用して、ゲームを開発し販売する場合のライセンスですが、2つのケースでライセンスがどのようになるのか質問です。
A. H.264の再生を行っていない。
B. H.264の再生を行っている。
それぞれのケースでデコーダーのライセンスが必要になるのかどうか教えてください。
また、B の場合、H.264動画を同梱し再生するので、コンテンツライセンスが必要になると思いますが、12分未満であれば無料、12分以上であれば料金が発生すると言う認識で良いでしょうか?
コンテンツライセンス料が無料の場合ですが、この場合もライセンス契約等は必要になりますでしょうか?

I have questions about the License for a case of regenerate H.264 using OS function.

1.
If we distribute game engine regenerates H.264 using OS function, is the License needed for decoder?
Specifically it is a case of distributing game engine which can video replay using Media Foundation after Window7.
Since it is a game engine, it depends on user whether the game using H.264 replay function will be distributed or not.
If License for decoder is required, if we make unable to replay for a case of H.264 video by checking input video file, won't it be treated as H.264 decoder?

2.
I would like to ask about the License to develop and sell game using game engine which is able to replay H.264 of above 1, please answer to my questions for the following 2 cases.

A. There is no regeneration of H.264.
B. There is regeneration of H.264.

Please advise whether the License of decoder is required for each case respectively.

Also for B, since H.264 video will be included and regenerated, I think contents License is required however is my understanding correct that it is free of charge if it is less than 12 minutes and we will be charged if 12 minutes or longer?

If contents License fee is free, will we still need to conclude the License contract?

As you are aware, MPEG LA offers our AVC License which provides coverage under patents that are essential for use of the AVC/H.264 Standard (MPEG-4 Part 10). Under the License, coverage is provided for end products and video content that make use of AVC/H.264 technology. Accordingly, the party offering such end products and video to End Users concludes our AVC License and is responsible for paying the applicable royalties. An upstream supplier of non-end products does not conclude our Licenses in order to provide coverage for its customer's branded end products.

With that as background, please allow me to address your specific questions below.

1) If your company will offer its own branded software product that does not include AVC/H.264 functionality, but will offer a software product that relies on AVC/H.264 encoders/decoders already residing on the End User's PC (for example, any AVC codecs that may be included in the Windows 7 Operating System), then your company would not benefit from concluding our AVC License. Instead, the party supplying the AVC/H.264 functionality on the PC would need to be licensed and would be responsible for paying the applicable royalties (for example, Microsoft).

On the other hand, if your company will offer its own branded software product that does include AVC/H.264 encoders/decoders, then your company would need to be licensed and would be responsible for paying the applicable royalties associated with the encoders/decoders it distributes.

There is no royalty for the manufacture and Sale of the first 100,000 AVC Product units in each Calendar Year under the AVC License. After the first 100,000 units in each Calendar Year, the royalty is $0.20 per unit up to 5M units in the year and $0.10 per unit for units above 5M units in the year. This royalty is subject to a maximum annual cap for an Enterprise of $6.5 million per year 2011-2015. A "unit" is a product that contains one AVC Decoder, one AVC Encoder, or a single product including one AVC Decoder and one AVC Encoder.

2) If your company will offer its own video game encoded on physical media in the AVC/H.264 format, and your company will be the party encoding the video game onto the disc, you are correct that your company will benefit from the coverage provided for Title-by-Title AVC Video.

The royalty for Title-by-Title AVC Video is either 2% of the price paid to the Licensee or $0.02, whichever is lower. These royalties only apply to Titles that are longer than 12 minutes in duration. As you mention, there is no royalty for Titles that are 12 minutes or shorter in duration.

Further, if your company will also include an AVC decoder that can only be used to decode the AVC Video on the disc (and no additional AVC Video content), no royalty would be payable for the AVC Decoder included on the disc.

For your background, Section 3.1.1.1 of the AVC License states that no royalties shall be payable under subsection 3.1.1 only in the event, "that Licensee Sells with AVC Video, for which a royalty is paid..., an AVC Decoder that has no function and no capability other than decoding the AVC Video, and only that AVC Video, with which it is Sold." In other words, if a Licensee offers Title-by-Title AVC Video (for which a royalty is paid) on physical media (e.g., CD-ROM) and it contains an AVC Decoder, and the decoder can only decode the AVC Video contained on the physical media, then no royalties would be payable for such decoder.

However, if no royalty is payable for the Title-by-Title AVC Video your company Sells (for example, if the total duration of AVC Video in the game is 12 minutes or less), any decoders included with the game would need to be accounted for and would be subject to applicable royalties.

To be clear, if your company will not be the party creating the discs containing AVC Video, then the replicator/duplicator creating the disc on your behalf would need to be licensed and would be responsible for the applicable royalties.


投稿者 Takenori : 20:02 | トラックバック

2014年02月23日

フルスクリーンとフリックインとモーダルWindow

現在の BasicDrawDevice のフルスクリーンは、ウィンドウを全画面化して描画するもので、Direct3D9 を使ったフルスクリーンではない。
Direct3D9 を使ったフルスクリーンでは、他の Window が前に出るとデバイスロストが発生する。
すると、描画できなくなる。
KAG3 の確認ダイアログなどは Window を使用しているので、これに該当する。
KAG3 のように複数 Window を使う形になっていると Direct3D9 を使ったフルスクリーンでは問題が出る。

Window8 では、フリックイン(画面外からのフリック)でメニューなどを出せたりする。
ゲームでも同じようにフリックインでメニューなど出せるといいが、上述のウィンドウの全画面化でフリックインすると標準(デスクトップ)のフリックインが機能し、標準のメニューが出る。
Direct3D9 を使いフルスクリーン化すると、これは機能しなくなり、ゲームでフリックインをハンドリングできる。

ここに相反する問題が存在する。
KAG3 のような複数 Window を使用する構造を止めるのが現実的な解決策。
ただ、ゲーム中の確認ダイアログは全てなくすというのは困る人もいるだろうから、何かしら代替策が必要。

Layer Tree Owner を使用した、複数の Layer Tree を持てる DrawDevice を作っているので、それによってこれらの問題は解決できる見込み。

投稿者 Takenori : 01:04 | トラックバック

2014年03月01日

HMAC とユーザー認証

ハッシュ関数の MD5 と SHA256。
キー付きハッシュ関数の HMAC-SHA256。
この3つを加えることを検討している。
MD5 は元々あるので、TJS2 から呼べるようにするだけだが。

HMAC-SHA256 があるとユーザー認証を作りやすくなる。
HMAC は、秘密キーと任意メッセージを使いハッシュを生成する仕組み。

具体的な認証方法は以下の通り。

1. ユーザーへシリアルコードと秘密キーのペアを配布。
(明示的に分離せずにシリアルコード+秘密キーで、単一のシリアルコードとして配布した方が楽)

2. ローカルでの処理
秘密キーを使いメッセージからハッシュを生成する。
メッセージには、シリアルコード、日時(タイムスタンプ)、バージョン、コマンド、(タイトルID)などを含んだ文字列を入れる。
生成したハッシュを base64 encode して文字列化。
メッセージの末尾に加える。
生成したメッセージをサーバーへ送信する。
ハッシュのみではなく、生のメッセージとハッシュを送信する、秘密キーは送信されない。

3. サーバーでの処理
送られてきたメッセージからシリアルコードを抽出する。
シリアルから秘密キーを検索し、ハッシュ以外のメッセージ部分を使い、ローカルと同じようにハッシュ生成する。
生成したハッシュと送られてきたハッシュを比較し、一致すれば認証成功とする。
ただし、一番最後に認証成功したタイムスタンプ以前のタイムスタンプが送られてきている場合は、その時点で認証失敗とする。
これは同じハッシュで何度も認証成功させないため。
また、あまり現在時刻とかけ離れたタイムスタンプも使えなくする。
認証成功後は成功を返せばいいが、何かデータを返した方が都合がいいので、秘密キーを用いて暗号化し返信する。
失敗であればデータは返信せず、結果のみ返す。

4. ローカル
認証結果を見て成功であれば、返信されたデータを秘密キーを用いて復号化する。


以上が認証の基本的な仕組み。
シリアルと秘密キーのペアがばれなければ、突破は困難。
サーバーで送信元IPアドレスも記憶し、短期間に複数個所から認証を要求された場合、認証を一時的にロックするなどするとキーの漏えいにある程度対応可能。
秘密キーは HMAC-SHA256 でハッシュの生成に使われるのみで、送信はされない。
安全な方法でシリアルコードと秘密キーをユーザーに渡す必要がある。
後、説明では省いているがURLエンコード/デコードもGETを使うと必要になる。

ユーザーを認証してデータを返すだけの仕組みなので、どのようなデータを返してコピーガードに役立てるかは別に検討する必要がある。
XP3 のヘッダー情報はサーバーからもらうなどすると、XP3 が単なる巨大なバイナリの塊になるので解析が面倒になる。
暗号化していればなおさら大変で、そのキーはサーバーからもらうようにするなども考えられる。
さらにデータ量の少ないスクリプトはサーバーから圧縮して送られてくるようになっているとやっかい。
すぐに思いつくのはこの辺り。
サーバーから返すデータが少なければ、サーバーには GAE を使用して認証サーバーとするのが楽ではないかと思われる。

吉里吉里Z で自前ビルドしやすくなったので、クラック耐性を強化する機能もあった方が良いということで検討中。
返されたデータの復号化以外はプラグインでも良いが。

投稿者 Takenori : 23:02 | トラックバック

2014年03月04日

メニュー関するすれ違いが分かった

メニューに関する疑問、質問について根本的なすれ違い原因が理解できたので書いておく。
とは言っても、現段階では何も解決するわけではないけど。


Q. 吉里吉里Z ではなぜメニューを消したのか?
A. 消してはいない。
実装していないが正しい。
Visual C++ でビルド可能にするには、新たに作らなければメニューは出来ない。
つまり、消したのではなく、作っていないということになる。

なぜか?
どうせ作るのであれば、タッチにも対応したメニューの方が良い。
そもそもタブレットではフルスクリーン時メニュー操作が出来なくなるので、何かしら代替機能が必要になる。


ここまでの話に反対する人はいないだろうというか、反対する理由は思いつかない。
なんで消したの?という疑問は正確ではなくて、なぜ同じ動作をするメニューを作らなかったの?という質問のほうが正確。
なぜ作らなかったのか?と言うと、作ってもその瞬間に仕様不具合を持ったものになるからという回答になる。

では、なぜプラグインでツール用のメニューは実装されているのか?
ツール用にメニューが必要だから、メニューがあったらお金出すという人がいたから。


で、タッチにも対応したメニューはいつできるの?
今余暇に作ってるから、気長に待てばそのうちできる。
飽きなければ。

投稿者 Takenori : 22:35 | トラックバック

Per-Monitor DPI

マニフェストを追加して Per-Monitor DPI に対応しているという設定を加えた。
Windows8 と 8.1 では、高解像度ディスプレイで自動的に拡大される機能がついている(8と8.1で少し機能が違う)。
自動で拡大してくれるが、そのせいで座標関係の取り扱いで問題も発生したりするため、対応しているとマニフェストを追加した。
この指定を追加すると自動拡大は行われない。
SurfacePro で起動してみるとかなり小さいサイズで起動される(小さく見えるが指定のピクセル数)。
拡大は自前で拡大率の指定ができるようにするか、フルスクリーンでプレイしてもらうこと前提にする必要がある。
エンジン側で解像度見て自動で拡大するかどうかの設定などがあった方がいいと思うが、その辺りは実装していない。

投稿者 Takenori : 22:48 | トラックバック

2014年03月08日

Android 対応検討

現在の仕様を維持して Android 対応する方法もあるが、その場合は無理が出たり、不自然になるところが出てくる。
また開発効率も落ちる。
そのため仕様変更も含めた修正を行うことを検討している。
羽々斬では互換システムということで、仕様維持して実装したが、失敗だった面もある。

以下、羽々斬の開発、吉里吉里Zの開発、ある程度 NDK によるビルドを行い事前調査した結果を元に検討した結果。
実際の Android 対応に関する工数見積もりなどについては後日。


マルチプラットフォーム化への前準備

1. クラス間の結合度を下げる
Extension で書いた機能を使って、既存クラスを疎結合にし、クラスをビルド時に取捨選択可能にする。
最小限必要なクラス + その他クラスを分ける。
移植時最小限必要なクラスを実装した後、順次他のクラス対応していくことでマルチプラットフォーム化しやすくなる。
また、ツール用に使いやすくなる。
スマートフォンなどで不必要なものを取り除くことで、コアのバイナリサイズを減らせる。
この対応とともにクラスや依存関係が分かりやすいフォルダ構成に変更する。
また、Git では全てを一つのリポジトリに入れると扱いづらいことがわかったので、現在のコア以外も全て入れている状態から、コアはコアのみのリポジトリにして、他は別リポジトリになるように構成を変更していく。

2. Screen クラスの追加
スマートフォンなどでは基本的にアプリは全画面で起動され、複数のWindowは使われない(もしくは使えない)。
その対応のために Window クラスに近いが複数作れない Screen クラスを追加する。
Android 環境では Window クラスは削除される。
Windows 環境では、単一 Window 前提で Screen クラスを使い作るか、TJS2 によって互換をとる。
Window クラスと Screen クラスはだいたい同じメンバーを持つ(環境依存なメンバーは Screen クラスからは排除される)。
レイヤーを使う場合は、Layer Tree Owner 基準で作ることになると思うので、スクリプトレベルで互換をとることはそこまで難しくはないはず。
KAG レベルであれば互換性について心配することはほぼない (Android等は制限の多い環境であることは意識する必要はあり)。

3. DrawDevice の機種依存部分を変更
一部 Windows 依存しているメソッドがあるので変更する。
ただ、Windows では DirectX 、Android では OpenGL ES 2.0 となるので、DrawDevice は機種依存するため互換性があっても意味がない面もある。
また、根本的な部分で互換性が取れなくなり、大きくインターフェイスを変更する可能性もある。

4. Bitmap が逆順に格納されているのを正順に変更
Bitmap が逆順になっているのを正順に変更する。
Scanline や Pitch など取得して処理している場合、この変更の影響は受けないが、Height が正の値の時は逆順として処理する形になっていると修正が必要となる。

5. パスデリミタとケースセンシティブ
パスデリミタ は、Windows では¥だが、他環境では / 。
Windows では、パスは大文字小文字区別せず、吉里吉里2/Z では内部的に全て小文字として扱われるが、他環境では大文字小文字は区別され、小文字に変換してしまうと、元のファイルにアクセスできない。
羽々斬では、大文字小文字を保持した元のファイル名を別に記憶し、必要時にそのファイル名でアクセスするという周りくどい実装になっている(もしかしたら記憶違いがあるかもしれない)。
パスデリミタについては、環境に合わせた変換が行われるようにする。
現在のケースインセンシティブな仕様は、ケースセンシティブなものへ変更。
ケースインセンシティブでの検索はオプション化(互換性のため。有効にするとAndroidでは確実に問題が出る)。

6. クリック、ダブルクリック
Window クラスではそのまま残すが、Screen クラスでは削除するイベント。
環境によって発生順序が異なり、問題の元。
Down/Up で処理する方が好ましい。

7.その他
その他 Android 対応時に Windows 依存が強い部分の仕様は変更される可能性がある。
実装時や調査時、思い出した時に追記する。

投稿者 Takenori : 23:04 | トラックバック

2014年03月09日

Android 対応必要項目と工数見積もり

必須部分で3人月 + テスト2人月
追加項目(優先度低いもの)を加えると4.6人月 + テスト2人月
他に考慮が漏れている項目がある可能性もある。

以下、詳細。

-----
事前対応項目

1. クラス間の結合度を下げる - 5人日
2. Screen クラスの追加 - 5人日
3. DrawDevice の機種依存部分を変更 - 0.5人日
4. Bitmap が逆順に格納されているのを正順に変更 - 0.5人日
5. パスデリミタとケースセンシティブ - 後述


-----
必須対応項目

OpenGL ES 2.0 対応 - 5人日
描画は最終的に OpenGL ES 2.0 で描画する ( Windows で DirectX 描画しているのと同じ )。

OpenSL 対応 - 5人日
サウンドは OpenSL によって対応する。

OpenMAX or ムービーテクスチャ対応 - OpenMAX 2人日
NDK は OpenMAX が使えるようだが、その場合 Window に対してのみで、全画面前提となるように見える(調査した範囲では)。
Java からは、ムービーテクスチャが使えるので、Java 経由でムービーテクスチャを使い動画再生可能にできると思われる。
初期は、OpenMAX での全画面再生を実装し、のちにムービーテクスチャの実装を試みる形になるかもしれない。

Screen クラス対応 - 7人日
各種入力イベント、描画への橋渡しなどを行う。

ファイルアクセス対応 - 3人日
ファイルアクセス部分、パスデリミタ、ケースセンシティブの対応が必要。
また、Assets へのアクセス対応も検討。
ただ、C++ からは Assets のフォルダへのアクセスが出来ないようなので、Java 経由が必要になる可能性もあり、どうするか検討する必要がある。
アクセス速度なども加味すると初回起動時に SD へコピーしてから実行する形が良いかもしれない。

スレッド対応 - 3人日
pthead による実装に変更する。

タイマー対応 - 2人日
Timer クラスは、独自スレッドでの実装だが、内部で使用しているタイマーは Windows 依存なので書き換える必要がある。

イベント対応 - 3人日
Android ではパイプを使用してイベント処理しているので、その形に応じたものへ変更する。
ただ、シングルスレッドではない場合は、独自の機構の組み込みが必要となる。

フォント対応 - 2人日
Android では /system/fonts にフォルトファイルが置かれているが、フェイス名などは分からない。
初回起動時に各ファイルを読み込んでフェイス名と対応付けなどして、保存して置くなどの対応が必要。
ただ、全端末で共通のフォントはないため、アーカイブにモトヤフォント(もしくは他のデフォルトフォント)を入れて対応する形が無難かもしれない。
フォント描画は、FreeType となり GDI は使用できない。
その関係で縦書き対応は初期は未実装。

各種システムメソッド対応 - 3人日
環境情報を取得するメソッドを Android に合わせて対応する必要がある。
Windows 固有のものは、Android 環境では使用できなくなる。

ドキュメント対応 - 4人日
Android 固有/Windows 固有の対応表や制限、新規に追加されたメソッドなどをドキュメント更新する必要がある。

ログ出力 - 0.5人日
コンソールではなく、LogCat への出力へと変更する。
また、出力を抑止することも可能にする。

ライセンス表示対応 - 0.5人日
使用するライブラリのライセンス表示のための対応を行う。
ライセンステキストを取得するメソッドを追加するなど。

グラフィック関係の固有部分対応 - 1人日
Bitmap などでWindows環境固有の部分があるので対応する必要がある。

固有メッセージ対応 - 2人日
エラーメッセージなどで環境固有部分の対応とWindowsリソースへ出力するスクリプトの変更が必要。

ライブラリのビルド対応 - 2人日
外部ライブラリを Android でビルドできるよう対応する。

ビルド環境整備 - 3人日
Android 用に楽にビルドできるように環境整備する。

メモリ初期化問題 - 1人日
Android では毎回なからずメモリが初期化されるわけではなく、メモリに余裕があってアプリ復帰した場合、前回のメモリ内容のまま復帰する問題がある。
吉里吉里ではグローバル変数(シングルトン)など使用しているので、この対処が必要。
メイン部分を Shared library 化し、読み込み、解放を行うことで毎回初期化が行われる形での対処を予定。


-----
以下は対応優先度が低いもの。
上のほうが優先度が高く、下のほうが低い
工数等の関係で初期は未実装となる可能性がある。

1. リリーサー - 5人日
他ツール等の都合上 Java での実装になる可能性が高い。
JRE, Android SDKの一部ツールが同梱される。
apk に全てのデータを組み込む or apk + xp3 という構成で生成する。
別ダウンロードなどが必要な場合は、別途自前でビルドする必要がある。

2. Vorbis 対応 - 3人日
Android (ARM) 環境を考えると Tremor を使用したものに書き換えた方が良いが、Opus で速度が出るのであれば、初期は Opus のみにしてもよい。
工数によって検討する。

3. NEON 対応 - 最小対応3人日
メソッド全て対応するのは工数がかかる。
ただ、まったく対応しないと速度的に厳しい可能性もある。
速度的に問題が出るようであれば、アルファブレンドなど使用頻度が高く速度に影響するメソッドのみは初期に対応することを検討する。

4. KAG3 対応 - 4人日
Window クラスを Screen クラスへ変更し、Yes/Noダイアログは書き換える。

5. プラグイン対応 - 4人日
Windows では DLL として動的読み込みされる形になっているものを、Android では Shared library として動的読み込みできるように対応する。
基本構造はそのままで持っていけるはずだが、読み込みの関数などは異なるのでその部分対応が必要。
また、プラグイン側も修正が必要。
その際マクロなどで共通化可能にする。
プラグインは、マルチプラットフォーム対応、Windows専用、Android専用の3種類に分類されることになる。

6. プラグインの組み込み化可能対応 - 2人日
プラグインとExtensionで共通のマクロやテンプレートでビルド可能にし、プラグインであればExtensionとして本体に組み込みできる形へ持っていく。
プラグインのほうが制約が多いので、プラグインを組み込みクラスへ持っていくのは、プラグインとして作られているのであれば可能な形にできるはず。
逆は個別に対応が必要になる。
Android であればプラグインとして独立している意味は薄い。
また、動的読み込みができない iOS のような環境へ対応する必要が出てきた時、本体へ組み込める形になっていないとまったく使えないことになる。

7. マウス入力 - 2人日
Android ではタッチ入力が主で、マウス入力はほぼ使われないことが想定されるので、優先度低。

8. キーボード入力 - 2人日
戻るキーは対応するが、他のキーは優先度低い。

9. ムービー再生(ムービーテクスチャ) - 3人日
最前面で単純に再生する以外の機能は実装が難しい可能性がある。

10. 文字入力 - 4人日
ソフトウェアキーボードとなるので検討しなければならないことが増える可能性あり。


-----
使えなくなる機能
ファイル選択・Susieプラグイン・クリップボードは Android では使用不可に。
他にも実装中に使用不可にする機能が出る可能性あり。

投稿者 Takenori : 06:03 | トラックバック

2014年03月20日

Lanczos3 を組み込んだ

拡大縮小コピーで Lanczos3 を組み込んだ。
dev_lanczos ブランチに入れている。
フルHDサイズで Core i7 でも 300ミリ秒強かかっているのでリアルタイムに使うのは難しい。
SIMD 化やマルチスレッド化でさらに速くできるが、とりあえずは使えれば良いということで入れる。
縮小の画質は以下の通り。
処理時間はかかるが綺麗。

lanczos_test.png

投稿者 Takenori : 12:51 | トラックバック

2014年04月04日

拡大縮小フィルタいろいろ

実装してみたフィルタ一覧。

ニアレストネイバーとファーストバイリニアは元のまま。
バイリニアとバイキュービックは今回実装した方法で実装しなおした。
バイキュービックは、シャープネスを指定可能にしたので、それによってシャープさが指定できる。
シャープネス -1.0 が標準的に用いられる値のようだ。
旧バイキュービックでは、ぼやけ気味でそれほど綺麗に見えなかったが、シャープネス -1.0 だと綺麗。
バイキュービックは、PhotoShop で標準になっていて、PhotoShop でもシャープネスをある程度指定できるので、この実装で同じような形に。
シャープネスの値をプラス方向に大きくするとぼやけていき、マイナス方向に大きくしていくとシャープになっていく。
やりすぎるとどぎつくなっていく。

他のフィルタは――
・Lanczos2
・Lanczos3
・Spline16
・Spline36
・面積平均
・Gaussian
・BlackmanSinc

Gaussianがぼやけているのを除いて、縮小ではほとんど同じ。
個人的には面積平均 と BlackmanSinc が好み。
バイキュービックでシャープネスをもう少し強くかけても綺麗に見える。
全て実装出来たら速度を一覧にするが、縮小ではクオリティーと速度から面積平均が使いやすいのではないかと思う。

resample_20140404

投稿者 Takenori : 23:10 | トラックバック

2014年04月06日

各種拡大縮小フィルタの実行速度

以下は、Core i7-477T での実行速度。
AVX2 が使用できるとなると Haswell 世代なので新しい CPU になる。
オレンジの枠は stFastLinear との速度比。
他はミリ秒。

stFastLinear は、拡大、または縮小後のサイズでサンプリングするピクセル数が決まるが、stLinear 以降は拡大後のサイズか縮小前のサイズと大きい方のサイズでサンプリングするピクセル数が決まるため、縮小はかなり不利。
また、拡大は AVX2 の方が SSE2 よりも遅くなっているので、SSE2 を選択した方が良いかもしれない。
これは AVX2 が 8 ピクセル単位なので、オーバーヘッドが大きいことによる。

拡大を見ると、速度的に stFastLinear の2倍程度になっており、十分実用的に使える速度。
また、縮小の方は前述の理由により差が広がっているものの、実行速度的には拡大よりも SIMD が効きやすいなどの理由で速くなっている。
表は、縮小の場合縦横 1/4 、拡大は 縦横 4倍したもので計測している。
サイズは、フルHD (縮小はフルHD サイズから 1/4、拡大は 1/4 フルHD サイズからフルHD サイズへ拡大 )。
クオリティーについては、前回画像を貼った通り。
前回書いたように縮小なら、面積平均が速度と画質で優れていると思われる。
拡大方向は、全体的に速度差が少ないので、一番きれいなものを選択してもいいと思う。
SIMD やマルチスレッドを意識して書いたため、それによって速度が伸びている。
以前の stLinear や stCubic は、リアルタイムで使用するのは厳しい速度だったが、これくらいの速度であれば CPU に応じて選択できる。
ユーザーがパフォーマンスかクオリティーを選択できれば満足できそう。

C、MMX は速度的に厳しいが、SSE2 を使えないことは少ないはず。
ただ、初期の SSE2 は遅かったので、Core 2 世代以降くらいからが実用的な範囲かもしれない。

stFastLinear や stNearest は、MMX までの実装なので、ここも AVX2 まで対応すればさらに速度が伸びそう。
ただ、stNearest はほぼメモリコピーと思われるので、対応しても意味がないかもしれない。
後、ブレンドやクリッピングの制限がなくなったので、使いやすくなった。
stFastLinear と stNearest はブレンド方式に制限があるので、逆転現象が起きてしまっている。
この辺りも考えると stFastLinear と stNearest も書き換えた方が良いかもしれない。

Fast がついている方は、固定小数点版のため誤差が大きい。
とは言っても、見た目ではあまりわからない程度。
Linear については、従来と名前がかぶるので、Semi-をつけた。

  C MMX SSE/SSE2 AVX/AVX2
  縮小 縮小 MT 拡大 拡大 MT 縮小 縮小 MT 拡大 拡大 MT 縮小 縮小 MT 拡大 拡大 MT 縮小 縮小 MT 拡大 拡大 MT
stNearest         0.13 0.06 1.17 0.51                
stFastLinear         0.51 0.22 7.17 2.18                
old stLinear 51.61   77.34                          
old stCubic 65.96   98.83                          
stLinear 38.39 9.84 70.23 16.98         5.03 1.46 15.32 3.92 3.10 1.14 18.26 5.23
  75.27 44.73 9.79 7.79         9.86 6.64 2.14 1.80 6.08 5.18 2.55 2.40
stCubic 66.02 17.27 97.89 22.41         9.14 2.72 15.93 4.15 5.26 1.97 18.56 5.28
  129.45 78.50 13.65 10.28         17.92 12.36 2.22 1.90 10.31 8.95 2.59 2.42
stSemiFastLinear         28.91 4.74 46.50 8.12 3.27 0.98 13.18 3.32 2.25 0.84 15.23 4.49
          56.69 21.55 6.49 3.72 6.41 4.45 1.84 1.52 4.41 3.82 2.12 2.06
stFastCubic         54.96 8.50 78.66 13.00 5.82 1.86 13.64 3.36 3.68 1.40 16.07 4.68
          107.76 38.64 10.97 5.96 11.41 8.45 1.90 1.54 7.22 6.36 2.24 2.15
stLanczos2 66.42 21.96 97.33 25.14         9.10 2.72 16.12 4.13 5.41 2.08 19.08 5.77
  130.24 99.82 13.57 11.53         17.84 12.36 2.25 1.89 10.61 9.45 2.66 2.65
stFastLanczos2         55.23 9.09 78.00 12.57 5.86 1.81 13.61 3.34 3.71 1.45 16.12 4.78
          108.29 41.32 10.88 5.77 11.49 8.23 1.90 1.53 7.27 6.59 2.25 2.19
stLanczos3 93.83 25.27 124.22 29.33         13.44 4.24 24.40 6.21 7.61 3.28 19.58 5.71
  183.98 114.86 17.32 13.45         26.35 19.27 3.40 2.85 14.92 14.91 2.73 2.62
stFastLanczos3         81.83 13.09 112.72 17.59 8.37 2.93 16.95 4.37 5.02 2.11 16.52 4.92
          160.45 59.50 15.72 8.07 16.41 13.32 2.36 2.00 9.84 9.59 2.30 2.26
stSpline16 65.64 16.81 97.57 21.79         9.01 2.60 15.94 4.03 5.27 1.99 19.20 5.56
  128.71 76.41 13.61 10.00         17.67 11.82 2.22 1.85 10.33 9.05 2.68 2.55
stFastSpline16         54.94 8.81 78.18 13.03 5.71 1.79 13.53 3.58 3.64 1.41 16.09 4.65
          107.73 40.05 10.90 5.98 11.20 8.14 1.89 1.64 7.14 6.41 2.24 2.13
stSpline36 93.15 24.56 124.35 28.64         13.33 4.10 24.23 6.07 7.48 3.19 19.59 5.65
  182.65 111.64 17.34 13.14         26.14 18.64 3.38 2.78 14.67 14.50 2.73 2.59
stFastSpline36         81.28 12.79 112.64 17.69 8.25 2.78 16.85 4.30 4.87 2.01 16.15 4.55
          159.37 58.14 15.71 8.11 16.18 12.64 2.35 1.97 9.55 9.14 2.25 2.09
stAreaAvg 27.75 6.92             3.80 1.14     2.46 0.94    
  54.41 31.45             7.45 5.18     4.82 4.27    
stFastAreaAvg         20.03 3.58     2.49 0.81     1.89 0.71    
          39.27 16.27     4.88 3.68     3.71 3.23    
stGaussian 65.35 17.67 97.24 24.41         9.09 2.62 16.06 4.11 5.29 2.01 19.12 5.73
  128.14 80.32 13.56 11.20         17.82 11.91 2.24 1.89 10.37 9.14 2.67 2.63
stFastGaussian         54.88 8.42 78.46 12.88 5.79 1.92 13.61 3.42 3.68 1.40 16.17 4.69
          107.61 38.27 10.94 5.91 11.35 8.73 1.90 1.57 7.22 6.36 2.26 2.15
stBlackmanSinc 126.39 33.64 154.99 37.19         19.06 5.65 25.23 6.35 10.87 4.26 19.93 5.81
  247.82 152.91 21.62 17.06         37.37 25.68 3.52 2.91 21.31 19.36 2.78 2.67
stFastBlackmanSinc         109.59 17.90 145.62 23.66 11.58 3.63 17.43 4.53 7.01 2.69 16.57 5.03
          214.88 81.36 20.31 10.85 22.71 16.50 2.43 2.08 13.75 12.23 2.31 2.31

投稿者 Takenori : 20:35 | トラックバック

2014年05月23日

JPEG XR の読み込みに対応

JPEG XR の読み込みに対応し、dev_jpegxr ブランチに入れた。
対応したバイナリはスナップショットに入れた。
現在のところ 32bppPBGRA と 24bppRGB のどちらかのみに対応。
グレースケールや HDRI 、 Motion JPEG XR などには対応していない。
jxrlib のフォーマットコンバーターはどうもおかしかったり、メモリリークしていたりと完成度があんまり高くない印象 ( jxrlib のメモリリークは直した ) 。
Windows なら OS 組み込みの機能を使ってもいいが、汎用性や問題を追いやすいなどの理由で jxrlib を使っている。
SIMD 対応して高速化なども考えられるし。

JPEG XR は、post JPEG を狙って作られたフォーマットの一つ。
他に JPEG 2000、WebP がある。
記憶では JPEG 2000 が一番古いはずだが、処理負荷が高いせいか全然普及していない。
と言うか、全部普及していない。

JPEG XR の持つ機能として以下のものがある。

・アルファチャンネル対応
・HDRI 対応
・Motion JPEG XR 対応 (アルファチャンネル付き動画に使える)

JPEG XR は Vista 以降なら標準で扱えるようになっていて、エクスプローラで JPEG などと同じようにサムネイルが見られ、ビューアで開けるなど、利便性が高い。

4:4:4 形式も選択できるので、JPEG など非可逆圧縮で目立ちやすい赤と青の劣化が目立ちづらくなっている ( 4:2:0 形式ではすぐに劣化に気づく部分 ) 。
ブロックノイズも発生しづらい仕組みになっているようで、高圧縮にしてもブロックノイズは見えない。
圧縮アルゴリズム的に 2DCG に適しているように見える。

圧縮率は 0~1 で指定する。
0.95 では、PNG に比べると 1/2 くらいのサイズになるが劣化しているのは気付かない ( サイズの減り具合は画像の種類による )。
0.8 で 1/4 くらいで、この辺りまでは劣化を感じられない。
これ未満だと劣化を感じられるようになってくる。
ただ、スマフォ等高繊細ディスプレイで見ると、ブロックノイズがないので高圧縮にしても綺麗に見える。
0.2 などで圧縮するとモスキートノイズがはっきりとわかるが、高繊細ディスプレイで見ると気にならない。

アルファチャンネルがある場合、アルファチャンネルをロスレスにするとあまり小さくならないので、少しは圧縮率を上げる必要がある様子。
0~255 ( 0 がロスレス ) の間で指定できるようになっているが、30 辺りが限度。


JPEG XR を使えば 0.8 なら 1/4 程度になるのでかなりパッケージサイズを削れそう。
Opus で音声は 1/2 以下に出来るようになったのと合わせて、組み合わせると今までの半分以下のサイズに出来ると思う。
後は、Windows 7 以降で使える H.264 対応と xp3 の LZMA 対応が加われば、各種データの圧縮方式が少し新しい世代になって、サイズは大きく縮む。

投稿者 Takenori : 10:41 | トラックバック

2014年05月30日

なぜ JPEG XR ?

なぜか WebP を推す意見を何度か目にするので、書いておく。

WebP は、JPEG の高圧縮版を目指して開発されているように感じる。
そして、WebP は 4:4:4 形式をサポートしておらず、4:2:0 形式になる。
これがどういうことかすぐにわかる画像が以下。

png_webp_xr.png

青と赤の劣化が激しい。
完全に違う色になっている。
4:2:0 は、色差成分が 1/4 サイズになるので、どうしても青と赤が劣化する。
青と赤成分の画像サイズが 1/4 になっているのに近い。
この性質から WebP をサポートしようという動機は薄い。
もちろんアルファチャンネルが後から追加されたように、後で 4:4:4 形式が追加される可能性はあるが、そんなにコロコロ仕様追加される画像フォーマットは面倒だと言う面もある。

「非可逆+アルファチャンネル」形式が欲しいと言うところが JPEG XR のサポート理由として大きい。
そういう意味では、JPEG 2000 でもいいが、Windows での使い勝手と言う意味では JPEG XR の方が良い。
JPEG 2000 と JPEG XR で画質や処理負荷では判断が難しい。
別に JPEG 2000 のサポートがあってもいいとは思うが、今のところそこまで組み込みたいと言う気持ちはない。

mozjpeg は? と言うピントの外れた意見も見た。
フォーマット的に mozjpeg は、ただの JPEG と全く同じである。

投稿者 Takenori : 18:45 | トラックバック

2014年07月10日

TJS2スクリプトのシンタックスチェック

TJS2 スクリプトを書いて、吉里吉里で実行したらシンタックスエラーが出て、直してまた実行と言うのは、他の IDE に慣れてくると徐々に辛くなってくる。
TJS2 もエディタでチェックして表示してくれないかなと言うことで、作ってみる。
C# だと、Azuki/Ann がエディタのベースとして使うのによさそうなので、これをベースに TJS2 のシンタックスハイライトに対応させ、コンパイラも組み込んでチェックするようにしてみた。

tjs2_coding20140710.gif

Java 版のコンパイラを C# に書き直して、エラーチェックのみ出来るようにして、エラーがあったら赤波線で表示するようにしている。
内部では、どんなエラーか保持しているので、ToolTip でエラー内容表示できるともう少し便利そう。
コンパイラはほぼそのまま持ってきているので、少しエディタに適していない。
エラーがあると、そのまま引きずられて最後までエラーだらけになることもある。
エディタ用にブロック単位でエラー復旧などして継続してコンパイル続けられる構造に変えた方が良さそう。
後、字句抽出もシンタックスハイライトにそのまま使えるはずなので、その辺りから構造を見直した方が良さそう。
内部で AST 持って、インテリセンスとかもできるとはかどるはず。
何度も吉里吉里起動してエラーチェックするのが面倒で作ったので、とりあえずはこれでも TJS2 コーディングがはかどりそう。
デバッガも統合して、吉里吉里用 IDE として使えるようになると便利そうだけど。

投稿者 Takenori : 03:41 | トラックバック

2014年07月20日

TJS2 ドキュメントジェネレータ その1

TJS2 スクリプトからそこに書かれたコメントを用いてドキュメントを生成するツールの途中まで。
ツールの基本構造は、TJS2 スクリプトを読んで、JSON 形式で出力する形。
実際にドキュメントとするには、JSON を読んで任意の形で出力する必要がある。
JSON になっていれば、そこから整形してドキュメントにするのは簡単なので、その手前までをやるツールがあればいいと言うことで、作ってる。

tjs2doc.zip

完全に構文解析するわけではないので、疑似コードでもある程度何とかなる。
今のところコメント内部は解析していないので、単純に comment 要素にコメントの中身がそのまま入るだけ。
javadoc 形式等でコメント内部を解析して、構造化するのはまた今度。
関数の引数も解析していないので、そこもまた今度。
字句抽出レベルでの文法エラーがあった場合は、エラーが出るはず。
エラーが出る場合はまだテストしていない。
実際にどんな形の JSON になるかは動かしてみればわかる。
その JSON 見れば意味もすぐに分かるはず。

これで1時間半かかった。
1時間くらいで出来ると思ったんだけど……

投稿者 Takenori : 23:53 | トラックバック

2014年07月21日

TJS2 ドキュメントジェネレータ その2

昨日の続き。

tjs2doc.zip

関数の引数の解析とコメントを javadoc として解析を行って、JSON に出力するようにした。
comment は raw にそのままの内容を、他のメンバに javadoc 解析した結果を入れる。
入る内容は以下のような感じ。
summary : ""
param : { name: "", desc: "" }
return : ""
throw : ""
author : ""
version : ""
see : ""
description : ""
unknown : ""

これで出力された JSON を使ってドキュメントを生成できる。
プラグインのドキュメント化することを考えると、@dll や @lisence 、@url、@category など追加してプラグインのドキュメントを作りやすくした方がいいかな。
後、今ファイルヘッダーコメント入れていないけど、それも入れた方が良さそう。
JSON からドキュメント生成するツール作る時に機能追加しよう。

今日はだいたい1時間だった。

投稿者 Takenori : 23:56 | トラックバック

2014年07月22日

保守サポート

必要な人に向けて吉里吉里Zで有償の保守サポート対応します。
対応するのは、本体と krmovie.dll の不具合。
他のプラグイン等は範囲外。
最初は年10万円。
状況によって金額は見直します。
必要な人はメール等で連絡ください。

今までは不具合対応など気が向いたら対応する形だった。
これからも基本変わらないけど、サポートが必要な人には迅速に対応していく。
OSS である保守サポートのような感じ。

誰でもそうだと思うけど――
仕事・やらなければならないこと > やりたいこと > その他
と言う優先順位だから、気が向いたらと言うのはプライオリティ低い。
自分が必要な機能の不具合修正や追加したい機能はサクサクやっていくけど、自分にとってどうでもいい不具合修正はかなり後回し。
開発中や瑕疵担保期間ならいいけど、もうだいぶ過ぎてしまっている。
有償でサポートするのなら仕事に格上げされるので、優先順位跳ね上がる。
金額は、かかった工数 / 契約数 だろうけど、最初は全くわからないので、10万円としておく。

投稿者 Takenori : 02:44 | トラックバック

2014年07月23日

部分的に1バイト文字にして速くなるか?

Slimmer and faster JavaScript strings in Firefox

これを読んで TJS2 でも同じように ASCII 文字列で格納すれば早くなるか試した。
結論を最初に言うとうまくいかなかったんだけど(部分的な変更では無理そう)。

TJS2 は文字列を tTJSVariantString で保持していて、21文字までなら固定長領域に格納される。
これを ASCII 文字列の場合は 43文字まで格納し、ASCII 文字列で比較すれば今までよりも長い文字列を固定長領域に保持でき、比較時も半分の長さを比較するだけで済む。
ハッシュの生成も半分のバイト長。
難点は、2バイト文字のポインタを得たい時には2バイト文字への変換とメモリ確保が発生してしまうこと。
で、この処理がキャストのオーバーロードで実装されていて、色々と使われている。
内部で文字列が tTJSVariantString で表されていればこの処理は使われることは少ない。
ただ、残念なことに tjs_char* で行われている処理が多い。
TJS2 の各種メンバアクセスのうち、PropSetByVS と言うメソッドだけが tTJSVariantString を使って検索していて、他のメソッドは tjs_char* で検索を行う。
だから、ASCII 文字列で保持しても出番が少ない。
全メソッドに ByVS 版を追加するとインターフェイスが変わってしまうし、量がある。
つまり、部分的な変更ではダメっぽい。

TJS2 は以下のような実装になっている。
文字列は全体で保持しているものがあり、同じ文字列の場合はだいたい共通のポインタを指すような実装になっているから、tjs_char* での文字列比較と言っても、一致するのならポインタ比較ですぐに終わる。
ポインタが一致しない場合は、文字列比較になる。
ASCII 文字列で格納するのはもうちょっと考えないとダメっぽい。

今回 tTJSVariantString の ASCII 文字列格納の実装に 1.5 時間くらいかかった。
ちゃんと動くようにもなったんだけど、速くならなかった。
理由は上述の通り。

投稿者 Takenori : 03:33 | トラックバック

2014年07月24日

TJS2 ドキュメントジェネレータ その3

tjs2doc.zip

squirrel プラグイン の manual.tjs を変換したもの

フレームとインデックス部分はないけど、それ以外の部分はだいたい動くようになった。
もうちょっと作りこめば、plugin フォルダ内の各プラグインの manual.tjs からドキュメントが生成できそう。

今日は、結局2.5時間くらいもかけてしまった。

投稿者 Takenori : 01:09 | トラックバック

2014年07月26日

TJS2 ドキュメントジェネレータ その4

複数ファイルを受け付けてマージして出力する形に修正した。
プラグインの manual.tjs をまとめて出力してみた。

プラグイン API リファレンス

マージして出すのは、TJS2 スクリプトから生成するときはいいとしても、このプラグイン API リファレンスのようなものだとちょっとごちゃごちゃしすぎか。
プラグイン名 クラス名...、プラグイン名 クラス名... と並ぶ方がプラグインの場合は、見やすそう。
出力方法をマージ方式かファイル分割方式のどちらか選択式にして、プラグイン名をコメント内にいられるようにしたら、とりあえずは完成かな。

デフォルト引数とプロパティの読み/書き対応、継承 の認識辺りも未対応だけど、区切りがついたら一度ソースコードを修正BSD辺りで吉里吉里Z プロジェクトにコミットするかな。

今日は45分くらい。
その後プラグインフォルダの manual.tjs の修正に時間かかった。

投稿者 Takenori : 00:38 | トラックバック

2014年07月29日

吉里吉里Z 64bit版試作

今日のお題は吉里吉里Z 64bit版。
2時間くらいかかって、ビルド通ってある程度動くところまで。

tvpwin64.zip

とりあえず制限として
・JPEG の読み込みは無効化しています。
・Phase Vocoder は動きません。
・WAVE で 16bit float 変換がある部分は動きません。
・グラフィックで SIMD 系が使用されないので、その辺りの合成は遅いです。
・FPU の精度設定か何か周りが何もしてません。
・例外発生時のCPUダンプ周りが怪しいかもしれません。

追加機能として
・CPU の機能は、AVX2 まで取得できるようになっているので、ログにいろいろ出ます。

後、Variant 型からポインタ変換している辺りや Win32 API 周りで問題があるかもしれません。


JPEG は SIMD libjpeg が 32bit なので、まだ対応してない。
libjpeg-turbo は、64bit 対応しているはずなので、そちらに差し替えれば対応できる。

Phase Vocoder や Wave は、アセンブリからイントリンシックに書き換えないとダメ。
グラフィック周りも、アセンブリからイントリンシックに書き換えるか、アセンブリを 64bit 対応させないとダメ。呼び出し規約周り合わせればいけるかも。

FPU は、_control87 で落ちるので無効化しといた。
64bit だと何か違うんだと思うけど、調べてない。

投稿者 Takenori : 02:15 | トラックバック

2014年08月01日

BOM 付き UTF-8 に対応

従来 BOM の部分も文字列として扱っていたので、BOM 付きの場合は文字が化けておかしくなっていたが、最初に BOM 付きかどうか判定するようにした。
BOM 付き UTF-8 は Visual Studio くらいだと思うが、あった場合も読み飛ばして読めた方がいいと言うことで対応。
また、Shift-JIS 指定されていても、UTF-8 の BOM がついていたら UTF-8 として読み込む。
これは UTF-16 の BOM と同様の扱い。

投稿者 Takenori : 15:02 | トラックバック

2014年08月05日

Media Foundation を使った再生

Windows7 で H.264 を再生しようとしたら DirectShow では再生できなくて、Media Foundation を使用しないと再生できない。
以前、Media Foundation で再生は出来るようにしていたので、それをブランチに入れた。
これでモードに vomMFEVR が追加されて、vomMFEVR モードで再生すると Media Foundation を使った再生になる。

その後実装を見ていたら IMFPMediaPlayer でプロパティを設定したりする作りになっていたが、IMFTopology を自前で作って再生する形に書き換えていたので、そちらにじわじわ書き換え中。
その場合 IMFMediaSession から IMFGetService を取得して、そこから各種インターフェイスを取得して、そのインターフェイス経由で設定する COM の面倒くさいところ盛りだくさんな形に。
IMFPMediaPlayer では簡略化されていて楽なんだけど、ファイル直接指定での再生は問題ないものの、吉里吉里のストリームを渡して再生する形ではどうにもうまく再生できなかったので、IMFTopology で自前で作る形に前に書き換えていた。
残りはプロパティやシークなどを埋めていくだけだけど、色々検索してインターフェイス探していかないといけないので大変。

Media Foundation は、Vista だと WMV くらいしかサポートしてない。
Windows 7 になると AVI / H.264 もサポートされているので、やっと使える感じに。

最初 IMFPMediaPlayer を使っていた関係で Windows7 以降用になると思っていたけど、IMFTopology で作るようにしていたので、Vista 以降ならそのままで動きそう。
Vista だと再生できるのは WMV のみなので意味がないけど。
Vista で H.264 再生しようとした場合はたぶん例外吐くはず。
XP だと起動時に DLL がないと言われて起動しないはず。
ビルド時の指定で XP を対象としたとしても。
そもそもプラットフォームツールセットを XP にするとビルドエラーがいろいろ出たはず。

1時間コーディングで色々と作っていたけど、1時間で完成させられるもので欲しいものが思い浮かばなくなってきたので、1日1時間好きなものを進めることにした。

投稿者 Takenori : 01:51 | トラックバック

2014年08月07日

vomMFEVR は全体的に非同期

Media Foundation を使った再生 に書いたように vomMFEVR モードが追加される予定で、使用すると Media Foundation を使った再生になる。
従来のモードはすべて DirectShow を使用して再生していたが、vomMFEVR モードは Media Foundation を使う関係上振る舞いに違いが出る。

vomMFEVR モードは、動画を開いた直後は各種プロパティは正しい値が得られない。
準備が出来たことを onPeriod の perReady で通知されるようにしたが、よく考えたら onStatusChanged で ready 通知された方が良いような気もするので、少し再考する。
まあ、それはともかく準備が出来たら非同期で通知されるので、その通知があった後に各種プロパティ値を取得する必要がある。
また、play や pause 、stop なども従来は呼び出した時、その中で onStatusChanged による通知が行われていたと思うが、これも非同期となり呼び出し後 onStatusChanged で通知される。
onStatusChanged 等を使って制御していた場合、この辺り挙動が変わるので注意する必要がある。
後、今のところ再生中以外はシークできない。
再生中以外のシークは何とか対応するかもしれないが、今は非対応。
Media Foundation が再生開始時に開始位置を現在の位置から行うか、指定の位置から行う形になっていて、それ以外では位置指定がないため、再生中以外はシークしないようにしている。
シークした瞬間再生が開始されるのであれば簡単だが、そうでない場合は状態の管理をよく考えないといけない。
プロパティについても再生に支障はない程度で、従来に比べサポートしているものは少ない。
ムービープレイヤーとして支障のないくらいの機能はあるが。

投稿者 Takenori : 01:11 | トラックバック

2014年08月10日

H.264 再生に対応

Media Foundation モードのテストが終わったので、マージした。
リポジトリにあるものや次のバージョンから使用できるようになる。
何度か書いたように vomMFEVR モードを指定すれば、Media Foundation での再生になり、Windows 7 以降であれば H.264 の再生が出来る。
Vista の場合は、vomMFEVR モードで何かを再生しようとした段階で例外が出るので、vomMFEVR モードが使用できるのは Windows 7 以降となる。
Windows 7 で、Media Foundation で再生できる形式は、H.264(.mp4) と WMV、AVI となっている。

以前書いたように onStatusChanged で ready が飛んでくる形に変更した。
open 後 read が来た後に各種プロパティの取得、設定が出来る。
現在、指定/取得可能なプロパティは以下の通り。
mode / visible / loop / playRate
left / top / width / height
originalWidth / originalHeight
fps / frame / position/ numberOfFrame / totalTime
audioVolume / audioBalance

セグメントループ等は使用できない。
onFrameUpdate も発生しない。
mixer モードのミキシングがなくなった形に近い。
audioBalance は、ステレオ(2チャンネル)の時のみ有効。

再生サンプルスクリプトは以下のような感じ。


投稿者 Takenori : 00:37 | トラックバック

2014年08月17日

theora のサポート

H.264 に続いて、theora もサポートした。
Vorbis + Theora の ogg ファイルが再生できる。
リポジトリのバージョンか、次のバージョンから使える。

theora の DirectShow フィルタは公開されているので、それを krmovie に組み込む形で対応した。
ただ、オリジナルはいくつかの不具合を含んでいたし、盛大にメモリリークしていた。
メモリリークの修正と画像フォーマット ( YUV / RGB32 ) が切り替わらない問題、RGB32 での上限反転等の修正を行い、問題なく再生できる形にして組み込んだ。
元は細かくフォルダ分けされていたが、krmovie にまとめるついでにフィルタ関連のソースコードはまとめてしまった。
不要になったファイルも削除。
krmovie.dll が 800kb ちょっとと大きくなった。
デバッグオプションの ENABLE_THEORA で有効/無効を切り替えられるようにはしている。
DirectShow フィルタでのサポートなので、vomMFEVR モードでは再生できない。
拡張子は ogg か ogv 。
音声と見分けるために ogv にしておいた方がいいと思う。

これで MPEG1/theora/WMV/H.264 の4つの動画フォーマットがサポートされることになった。
CPU 負荷や画質、容量などを考えて選択できる。

対応中ソースコード読んで修正していると、何度も一から作った方が早いんじゃないかと言う考えが浮かんだが、何とか問題点は修正できた。
ただ、ちょっと効率上どうかなと思う部分も散見されるので、もしかしたまた手を入れたり、位置から作る可能性もあるかも。
もし Media Foundation 側でも対応しようとしたら、一から作ることになるけども。

投稿者 Takenori : 18:44 | トラックバック

2015年02月22日

NaN の判定

Math.isNaN = function (value) { return (typeof value == "Real" && (string)value == "NaN"); };

IEEE 754 の規定で NaN が絡む == は常に false、!= は常に true 。
TJS2 もそれに準じている模様で、NaN と比較しても false となり判定できない。
文字列化すれば "NaN" が返ると言うことで、上述の判定案。
一方でも NaN なら常に false と言うのを利用して判定する方法も考えられるが、最適化などによって将来的に結果が変わる可能性なども考慮すると文字列で比較が安定か。
判定関数を本体に組み込んでしまうのが一番だと思うが。

投稿者 Takenori : 22:20

2015年03月03日

2種類の乱数生成メソッド

吉里吉里2/Z は、乱数生成メソッドが2種類ある。
Mersenne Twister を使う Math.RandomGenerator クラスと _lrand/rand を使う Math.random メソッド。
シードを指定できるかどうかと乱数の品質からみんな Math.RandomGenerator の方を使って、Math.random を使っている人はいないと思っていたんだけど、どうもそうではない様子。

実際に Math.random を使う理由としては手軽さだろうか?
Math.RandomGenerator のインスタンスを生成する1行の差でしかないと思うが、とりあえず実験やテスト用に動けばいいと言う用途なら Math.random で十分だと思う。
リリースするゲーム等で使用するのに、この1行の差を惜しむことは少ないと思うが、楽なのは間違いない。

速度が速い方が良いと言うことで、Math.random を使っている人もいるだろうか?
速度が理由と言う人は、実際に計測してみたことはあるだろうか?
TJS2 で実際に呼び出して計測してみると、吉里吉里2では10%、吉里吉里Zでは2%ほど、Math.random が速い。
吉里吉里Z の Math.random を XorShift に書き換えてみると 12% 程度になる。
VC の rand が遅いのは、たぶんマルチスレッド用のロック周りの処理があるためではないかと推測される(ソースコードがないので想像)。
bcc については、ソースコードを見るとスレッドごとに状態を持つ実装になっているので、比較的オーバーヘッドが少ないのであろう。
この程度の差のために Math.random を使っているのだろうか?
実際の計測は、以下のようなスクリプトの実行時間を System.getTickCount で挟んで計った。

var m = Math;
for( var i = 0; i < 1000000; i++ ) {
 sum += m.random();
}

Math.random() と呼び出していないのは、そのように記述するとだいぶ遅くなるから。
以下のように記述した Math.RandomGenerator を使用するスクリプトの1.5倍以上遅い(2とZで30%程度差は異なる)。

var rng = new Math.RandomGenerator(0);
for( var i = 0; i < 1000000; i++ ) {
 sum += rng.random();
}

Math.random() と書いて何度も呼び出していたら、速いから使うと言う理由は完全になくなる(逆に遅くなっている)。
Math.RandomGenerator をクラスメンバに持って呼び出したとしても、Math.random() と呼び出す方が遅い。

つまり、TJS2 スクリプトとして実行する上では、無視できるくらいの速度差でしかないことになる。

投稿者 Takenori : 18:22

2015年03月17日

疑似乱数1

前回の乱数のエントリーでどう違うのか認識していないのではないかと言う指摘を見たので、説明を試みる。

Math.random/Math.RandomGenerator によって生成される乱数は、疑似乱数で真の乱数ではない。
これら疑似乱数は、長周期で偏りの少ない数列を生成する数学的な関数によって作られる。
つまり、何度も乱数を取得していれば、いつかは同じ値の繰り返しになる。

真の乱数があるとすれば、次に出る数は不明で、出る数はその時ごとに全ての数が等確率になるが、疑似乱数は次に出る数は決まっており、何度も値を得れば出る数の確率が出来るだけ均等になるように考えられている。
少し乱暴になるが、疑似乱数は様々な値の入った配列を最初から順に見ていき、最後までいくとまた最初から見ていくのと同じような動作となる。

疑似乱数で必要になる要素には以下のようなものがある。

1. 出る数は偏りが少ないようになっている。
2. 同じ数の並びが頻繁に繰り返し出ないように、ある程度長い周期を持っている。
3. 生成される数値の幅がある程度広くなっている。

1.は、たとえばサイコロで1と2ばかり出るようでは困る。
そのような動作をしていると不具合だと思われることもあるだろう。
2.は、1,2,3,1,2,3,1,2,3…と同じ順で繰り返し出ていれば次に何が出るか丸わかりだし、ゲームとして成立しない場合もあるので、一見繰り返しがわからないくらい長い周期が必要。
出来るのなら、全く繰り返していない方が望ましい。
また、1と関連するが奇数ばかり出たり、奇数、偶数、奇数と繰り返されたりするなど、規則性があるように見えて困る場合もある。
3.は、たとえば1~10のいずれかの値が欲しいのに、6までしか出ないと、7~10の値が全くでなくて困る。
6が10になるようにスケーリングして10までの数値が出るようにもできるが、歯抜けになってしまい、出ない数字が出来てしまう。
疑似乱数では必要とする値の幅以上の乱数が生成されないと不都合がある。


吉里吉里2の Math.random は bcc の _lrand が使用されており、_lrand は乗算合同法を使っていると書かれている。
ソースコードを見ると線形合同法と同じように見える。
乗算合同法や線形合同法は、乱数を生成するアルゴリズムの名前。
吉里吉里Z の場合、vc の rand が使用されている。
実装は不明だが、0 ~ 32767 の値を返すと書かれている。
線形合同法で実装されていると思われるが、実際にどういう実装かは不明。

線形合同法は、下位ビットを使用すると偏りが大きかったり、奇数/偶数の偏りが見られるなどの問題が知られている。
また、二次元座標などペアで使うと規則的に並ぶ下図のような問題もある。

201403lcgs.png

これらの問題は、下位ビットは使わず、上位ビットを使うことで回避できる。
bcc の実装はそのようになっており、この問題は発生しない。
vc でもこの問題は発生しないため、同じような実装になっているものと思われる。
つまり、吉里吉里2 も Z もこれらの問題は関係ない。
そもそも Math.random は 0 ~ 1 の数値で返す形になっているので、下位ビットよりも上位ビットの方が影響が大きくなり、この問題はあったとしても影響しない(意図的にやらないと下位ビットのみを取り出せない)。

実際に上図のように Math.random を使って点をプロットして見ると以下のようになる。

201403mathrandom.png

Math.RandomGenerator でも同じようになる。

201403mtrandom.png

xorshift を使うと以下。

201403xorshift.png

だいたい同じようになる。
これを見る限りそこまで大きな偏りがあるようには感じない。
ただ、局所的な偏りが発生しているかどうかはわからない。

続く

投稿者 Takenori : 01:23

2015年06月12日

メモリの断片化によるメモリ確保失敗に関して

最近話題に上がっていたので、詳しい説明を書く。

メモリが確保される状況を図にして説明する。

memory_fragment.png

上図は、Bitmap 等大きなメモリを4回確保した後、3個目オレンジのメモリを解放(1,2,3,4)。
スクリプトの変数等の小さいメモリを確保(5)。
2個目紫を解放して、スクリプトの変数等を確保(6)。
1個目青を解放して、スクリプトの変数等を確保(7)。
Bitmap 等大きなメモリ(黄色)を確保(8)。
と言ったメモリ確保の流れを図示している。

こうなった状態で再度Bitmap 等大きなメモリを確保しようとしたら確保できなくなる。
図では13個開いているので、5個のメモリは確保できるはずだが、連続した領域として確保できないので、確保に失敗する。
図の確保順はメモリ管理アルゴリズムがファーストフィットの場合で、ベストフィットだったとしたら6の段階で紫があった位置ではなく、オレンジがあったところ、緑の右隣が確保され、紫のところは5個の連続した領域が残ることになる(図の 6')。
ファーストフィットは一番最初に見つかった確保可能な領域を使用するもので、ベストフィットは空き領域の中で欲しいサイズ以上の出来るだけ近いサイズの領域を使う。
ファーストフィットは、最初に見つかった領域を使うので早くメモリ確保できるが、ベストフィットは空き領域のリストを全部調べるので少し処理時間が延びる。
ただし、ベストフィットの方がフラグメンテーションが起きづらい(6',7',8')。
8' の後もメモリ確保が出来る。
ただ、フラグメンテーションが置きづらいと言っても、確保のされ方によっては断片化が起きる。

以上がフラグメンテーションが起きてメモリが確保できなくなる理由や、メモリ管理アルゴリズムによって差が出る理由。

吉里吉里2 と吉里吉里Z で Bitmap メモリが確保できないと言うエラーが出る率が違うのは、メモリ管理アルゴリズムの差によるものと思われる。
Windows Vista 以降ではフラグメンテーションが起きづらいアルゴリズムが採用され、吉里吉里Z ではその恩恵を受け、吉里吉里2 は C++Builder のメモリ管理アルゴリズムが使われフラグメンテーションが起きやすいのではないかと推測される。

図では、緑のセルは解放されていないが、実際は確保されたり解放されたりする。
例えば、7の段階で紫だった位置の緑のセルが解放されれば間に連続した空き領域が出来る。
厳密には、分断された状態で空き領域のリストが保持されているので、コンパクションと言われる連続した空き領域をひとまとめにする処理を行わなければ大きな連続した空き領域にはならない。
つまり、ずっと確保されたままにならず、メモリ コンパクションが行われるのならフラグメンテーションの影響でメモリが確保できなくなることはない。

KAG3 では、既読判定のためラベル通過ごとに変数が増える。
また、その変数はロードし直したりしなければ、ずっと確保されたままになり、定期的にメモリ確保が発生するので、メモリのフラグメンテーションが発生しやすい。
確保されたままであれば、コンパクションの意味はないので、メモリ管理アルゴリズムによっては早い内にメモリ確保に失敗する状況が発生しうる。
ベストフィットなどのアルゴリズムであれば、そうそう確保に失敗する状況にはならない。
どれぐらいの規模(連続したプレイ)で「ビットマップ用メモリを確保できません/……」と言ったエラーが発生するのかはわからないが、シナリオが長くなり、画像サイズが大きくなってきたことで、この問題が顕在化しやすくなっているのではないかと思われる。

吉里吉里Z では、この問題は発生しづらくなっているとはいえ、発生しないわけではない。
そこで、さらに発生する率を減らすため、Bitmap を確保するメモリ領域を分離する設定がある(デフォルトは有効にはなっていない)。
Bitmap のような大きな領域とその他の小領域のメモリ領域を分離すると、大きな領域を解放後の領域に小さいメモリ確保が発生することがないので、フラグメンテーションの発生が少なくなる。
また、Bitmap の領域を分離するとともに、Bitmap の領域解放後は毎回メモリのコンパクションも行っているので、常に連続した大きな領域が開いている状態を維持しようとしている。
この辺りの設定などについては、以下のエントリーに書いている。

メモリ断片化低減対策
グローバルヒープもHeapCompact可能に

投稿者 Takenori : 21:04

2015年08月14日

カラー絵文字

coloremoji20150814.png

実装に当たって色々と悩んだので、方法等を書いておく。

FreeType を使ってカラー絵文字サポートするサンプルは How to render color emoji font with FreeType 2.5 にあった。
基本的にはここに書かれている方法で出来る。
後は、Skia の実装も参考になる。

実装方法はいいとして、表示するには実際の絵文字の文字コードが必要になる。
Emoji Unicode Tables に一覧がある。

フリーのカラー絵文字フォントは、Android の NotoColorEmoji.ttf が Apache License 2.0 で使える。
このフォントは上の一覧の Android の欄で書かれているものと同じものが入っている。
ただ、Android 欄でモノクロになっている絵文字は含まれていない様子。

カラー絵文字は複数サイズの PNG 画像が入っているだけなので、任意サイズが欲しい時は自分でリサイズする必要がある。
また画像はアルファ乗算済み。

絵文字のコードポイントの値を見ると 16bit 超えていて、UTF-16 だとサロゲート・ペアが必要になる。
吉里吉里3 から持ってきていた UTF-8 - wide char の変換をするメソッドで通らないところがあると思っていたが、吉里吉里3 の wide char は 32bit だったことを思い出した。
つまり、変換メソッドで 16bit の範囲を超える場合は、サロゲート・ペアの文字に変換して UTF-16 とするのが吉里吉里Z では期待した動作となるはず。
ここを書き換えると UTF-8 で書かれたスクリプトにある絵文字が適切に UTF-16 へと変換されるが、内部の処理はサロゲート・ペアに対応していない。
とりあえずは文字描画部分のみ対応すれば描画できるのでそこだけ対応。
正式に対応するのなら、文字列処理や KAGParser などもっと広範囲な対応が必要。

絵を準備して文字の間に表示すれば、カラー絵文字と同じことが出来るわけで、カラー文字に対応する必要性については考えてしまう。
現在の実装だとカラー絵文字を表示する前にフォントを切り替える必要もあって使い勝手が悪い。
絵文字用のフォントとその他を指定して、絵文字が現れたら自動で切り替えるようにスクリプトなどで wrap するなどしないと使いづらい。
文字として気にせず利用できるのと、フォントがあれば複数の絵文字が標準的に使えると言う利点はある。
後、画像を自前で準備すれば、任意の画像を文字として使えるので、その点は便利そう。
カラー絵文字フォントを作るツールも準備されている。
Tool to build color fonts using Google color-font format
思い付いた時の電球マーク等立ち絵にアニメーション付与されるエフェクトを文章中の絵文字に割り当てて、その絵文字がメッセージに表示される時に自動的に対応したエフェクトも出すような動作をさせるのなら、楽にエフェクト指定出来ていいかもしれない。

はまりポイントとして FT_Load_Glyph に渡すフラグで FT_LOAD_COLOR は必要として、FT_LOAD_NO_BITMAP は指定しないのはわかるが、FT_LOAD_NO_SCALE も指定してはいけない。
FT_LOAD_NO_SCALE を指定すると内部で FT_LOAD_NO_BITMAP も設定されてしまう。
最初従来の実装に FT_LOAD_COLOR フラグ足すと Invalid_Size_Handle エラーが返ってきてうまくいかないし、FT_IS_SCALABLE が false になるので、FT_LOAD_NO_SCALE を指定したらエラーは返ってこなくなったからそのようにしたが、そうすると bitmap が得られなかった。
結局、カラー絵文字の時は FT_LOAD_COLOR のみを指定するとエラーもなく、bitmap も得られた。
また、デフォルトでは FT_CONFIG_OPTION_USE_PNG がオフになっているので、これを有効にして FreeType をビルドする必要がある。

投稿者 Takenori : 01:38

2015年11月06日

吉里吉里2/Zに脆弱性があると言う話

TYPE-MOON 製の複数のゲーム製品における OS コマンドインジェクションの脆弱性

ニュースサイトによっては間違っている内容など書かれていたりするので、何が問題で具体的にどういうことかを説明してみようと思います。

一言で言えば、「吉里吉里2(Z)は、セーブデータの中にTJS2スクリプトを入れて実行できる。」と言うことです。
また、TJS2 スクリプトは任意の実行プログラムを実行することが出来ます ( System.shellExecute、厳密には TJS2 ではなく吉里吉里の機能 )。

この2つによって「OS コマンドインジェクションの脆弱性」があると言われているようです。
普通にゲームをプレイしていれば何も問題ないわけですが、ネットで拾ってきたセーブデータに差し替えたら予期しない結果になるかもしれないと言うことです。
これを脆弱性と言うか、対応をとるかについては開発者の意見は様々ですが、「まあデータはデータとしてだけ読み書きできる方がいいよね」と言うのはおおむね一致した見解のようです。
ネット上でのセーブデータ交換がどの程度行われているかわかりませんが、やっている人がいるのは事実です。

以上がこの脆弱性の詳細ですが、吉里吉里Zでの対応はどうするかについて――
データ読み込み専用のメソッドを追加することにします。
具体的にはDictionary/Array に loadStruct メソッドを追加します。
saveStruct と対称になるようにして、データのみの読み込みだとわかりやすくします。
ただ、最初はバイナリモードで書き出したデータファイルのみの読み込みのみ対応します。
バイナリデータは、通常のスクリプトのバイトコードとフォーマットから完全に分離していて読み込みも内部的に別となっているため、呼び出し口さえ追加すれば対応できます。
その他テキスト系の読み込みはパーサが共通のため少し対応に時間がかかります。
また、対応するのなら同時にテキストモードでの読み込み速度の改善なども行いたいところです。

本体での対策以外に対策が可能かどうか?
プラグイン作れば可能ですし、TJS2で文法チェックだけするのでも防げます。
吉里吉里2/Zを使ったゲーム全てにこの脆弱性があるわけではなく、対策を行っているゲームも存在するようです。

追記
吉里吉里Z スナップショットにバイナリモードで書き出したデータのみ loadStruct で読み込めるものを追加。

追記
W.Deeさんより
System.shellExecute = null;
を実行して、このメソッドを使えなくすると言う対策もあると言うことなので追記。

投稿者 Takenori : 17:09

2015年12月22日

Entyの支援でやる気出てきた

Enty/吉里吉里Z保守開発

Enty には11月8日に登録していたが、特に何もなくそうだよなぁと過ごしていたけど、12月12日に初支援があって、これは何かやらねばとやる気が出てきた。
100円/月ってことで、金額をそのまま作業時間とすれば1分/月くらいになってしまうだろうか。
GitHub のプルリクエストでソースコードレビューしてマージボタン押すくらいでも1分は過ぎてしまう。
でも、それよりも何よりも実際にお金出して支援してくれる人がいると言うのがうれしい。
1ヶ月以上何もなかったので余計に。

投稿者 Takenori : 02:52

2015年12月23日

マルチプラットフォームのGUIツールキット

GUI 周りを環境ごとに書くのは大変なので、良い物がないか探すもやはりどれも用途に合わない。
C++ で扱えて候補に挙がるとしたら wxWidgetQtFLTK 辺りだろうか。
ただ、どれも大きすぎる。
過去何度か探したが、イマイチしっくりこない。

吉里吉里Z用では、widget を色々と配置してあれこれすると言うのは全く必要なくて、ほとんど Window の表示周りが出来ればいいだけなので、よくある GUI ツールキットはどれも大きすぎる。
少しだし環境ごとに書くしかないかとも思うけれど、Mac OSX での GUI 周り書くの面倒くさい気持ちが大きくて大変。
C++ で書くなら Carbon で、Carbon 廃止 Cocoa を Objective-C で、Swift で書け、ただし C しか呼べないから C++ のラッパー書いて、とか言うのを見て、これは書きたくないねとなる。

Mac/Linux は Java に任せてしまうのがいいだろうか?
羽々斬で Java で書いた吉里吉里2の Window クラスがあるから、必要な部分をうまく切り分けて、C++ の 吉里吉里Zから呼べるようにすれば、GUI 周りはもうほとんどできているようなもの。
Java が必要でエントリーポイントも Java からになるけど、昔は OSX には Java が同梱されていた影響か Java アプリそこそこあるし、Mac 版の呼び出し元が Java でも大丈夫そう。
Mac 版はそこまでやる気が起きないから、環境依存部分でライブラリに頼れないところは、羽々斬の Java で書いたものを使って作るのがまずは現実的か。

と、思ったが、GLFW はどうか。
何気なく GLUT が目に入って、GUI ツールキットではなく、OpenGL 系で GUI サポートがあるライブラリだと、GUI 周りはシンプルではないかと。
freeglut 見てみたけど、GLUT をそのまま進めたような感じで少し扱いづらい。
GLFW を見てみるとかなり理想的な感じだ。
使い方等見てみると、Win32 API でウィンドウ表示してごそごそするのとあまり変わらない。
Window の表示とそのイベント処理くらいしか出来ないが、それで十分。
メニューもないけど、吉里吉里Z ではプラグイン化して非推奨とし、ツール用としているからいいだろう。
ファイルオープンダイアログ等がないのは少し気になるかもしれないけど、どうしても必要なら個別実装してもかまわない範囲かな。
描画も非Windows なら OpenGL だろうしちょうど良さそう。
まあ、ほとんど CPU 描画で最後にテクスチャ貼る部分くらいしか OpenGL 使われないが。

Android は自前でやらないと勝手が悪い部分が多いから自前実装だろうな。

投稿者 Takenori : 15:04

2016年01月02日

吉里吉里ZのCPU判定処理を変更したので確認のお願いと64bit版

アセンブリで記述されていたCPU判定処理をイントリンシックを使いC++で書き直し、SSE2以降のSIMD命令対応判定を追加しました。

CPUの判定が正しく機能していることを確認していただけると助かります(特に非IntelのAMDなどのCPUで)。
この対応で SSE2 より後の命令を入れやすくなったのと、64bit 対応等がやりやすくなります。

CPU判定処理変更版 + 64bit版履歴
2016/01/02 18:15 : cpuid_check_20160102.zip 初回リリース
2016/01/02 18:42 : cpuid_check_20160102_002.zip Corei7 920 / Atom Z3735F で判定失敗、AVXレジスタ判定修正後問題なく動作
2016/01/02 19:13 : cpuid_check_20160102_003.zip AMD A10-5700 TSC が間違っていたので修正後一致
2016/01/02 21:06 : cpuid_check_20160103.zip RDTSCP,RDRAND,RDSEEDを追加、FPU判定をcpuidから取得

確認していただきたいのは、以下の二点です。

1. check.bat と check_old.bat を実行比較して「(info) CPU #0 : FPU:yes MMX:yes」~ 「(info) finally detected CPU features :」の内容で TSC までの yes/no と 末尾の「Intel(GenuineIntel) 」などの文字列、EAX=の後の値、EBX=の後の値が同じかどうか。
2. SSE2以降のSSE3 ~ AVX2, FMA3, AES(-NI) の yes/no が他のcpuz等のソフトで表示される対応状況と同じかどうか。


確認後、ツイッターやコメントで以下の部分をコピペして報告もらえると助かります。
「(info) CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:yes AVX2:yes FMA3:yes AES:yes Intel(GenuineIntel) [Intel(R) Core(TM) i7-4770T CPU @ 2.50GHz] CPUID(1)/EAX=000306C3 CPUID(1)/EBX=00100800」

----

結果をもらったものなど
CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:yes AVX2:yes FMA3:yes AES:yes Intel(GenuineIntel) [Intel(R) Core(TM) i7-4770T CPU @ 2.50GHz] CPUID(1)/EAX=000306C3 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:yes AVX2:yes FMA3:yes AES:yes Intel(GenuineIntel) [Intel(R) Core(TM) i7-5820K CPU @ 3.30GHz] CPUID(1)/EAX=000306F2 CPUID(1)/EBX=00100800

SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A :no AVX:no AVX2:no FMA3:no AES:no Intel(GenuineIntel) [Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz] CPUID(1)/EAX=000106A5 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:yes AVX:yes AVX2:no FMA3:yes AES:yes AMD(AuthenticAMD) [AMD A10-5700 APU with Radeon(tm) HD Graphics ] CPUID(1)/EAX=00610F01 CPUID(1)/EBX=00040800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:yes AVX2:no FMA3:no AES:yes Intel(GenuineIntel) [ Intel(R) Core(TM) i7-2720QM CPU @ 2.20GHz] CPUID(1)/EAX=000206A7 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:no AVX2:no FMA3:no AES:no (略) [Intel(R) Core(TM) i7 CPU 930 @ 2.80GHz] CPUID(1)/EAX=000106A5 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:no SSE42:no SSE4A:no AVX:no AVX2:no FMA3:no AES:no Intel(GenuineIntel) [Intel(R) Core(TM)2 Duo CPU U7500 @ 1.06GHz] CPUID(1)/EAX=000006FD CPUID(1)/EBX=00020800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:yes AVX2:no FMA3:no AES:yes Intel(GenuineIntel) [ Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz] CPUID(1)/EAX=000306A9 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:no SSE42:no SSE4A:no AVX:no AVX2:no FMA3:no AES:no Intel(GenuineIntel) [Intel(R) Core(TM)2 Duo CPU U7600 @ 1.20GHz] CPUID(1)/EAX=000006FD CPUID(1)/EBX=00020800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:yes AVX2:no FMA3:no AES:yes Intel(GenuineIntel) [ Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz] CPUID(1)/EAX=000306A9 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:no AVX2:no FMA3:no AES:no Intel(GenuineIntel) [Intel(R) Core(TM) i5 CPU U 470 @ 1.33GHz] CPUID(1)/EAX=00020655 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:yes SSE42:yes SSE4A:no AVX:no AVX2:no FMA3:no AES:yes Intel(GenuineIntel) [ Intel(R) Atom(TM) CPU Z3740 @ 1.33GHz] CPUID(1)/EAX=00030673 CPUID(1)/EBX=00100800

CPU #0 : FPU:yes MMX:yes 3DN:no SSE:yes CMOVcc:yes E3DN:no EMMX:yes SSE2:yes TSC:yes SSE3:yes SSSE3:yes SSE41:no SSE42:no SSE4A:no AVX:no AVX2:no FMA3:no AES:no Intel(GenuineIntel) [ Intel(R) Atom(TM) CPU Z2760 @ 1.80GHz] CPUID(1)/EAX=00030651 CPUID(1)/EBX=00040800
----
64bit版

基本的に前回の吉里吉里Z 64bit版試作と同じです。
最新版にマージして dev_64bit ブランチに入れました。

Phase Vocoder は、主に開発時に使用されると思われるので、後回しでいいとして JPEG 読み込みとグラフィック部分の SIMD 対応は先に対応して、64bit 版を使えるようにしたいところ。
64bit 化でどのような不具合があるかわからないので、今後リリース時にテスト版として 64bit を同梱して確認してもらう機会を増やしていくことを考え中。
プラグインは 32/64bit の両方で必要になるので、64bit の場合は plugin64 フォルダを優先的に読み込むように変更して、32bit 版の dll は plugin フォルダ、64bit 版の dll は plugin64 フォルダに入れることで共存可能にすることを検討中。

64bit 版が出来ても、使用可能メモリ量が増えると言うメリットはゲームでは薄いので、あまり要望としてはないだろうか?
Android や Mac OSX に対応するとなると 64bit 対応も入ってくるのであった方がいいと思う。
後は、プロセス一覧で(32ビット)と言う注釈がなくなるのとネイティブ64bit対応している感がすっきりして気持ちいいくらい。

投稿者 Takenori : 18:15

2016年01月03日

CPU判定処理の結果など

もらった結果と手持ちの9台での結果を一覧にした。
前回エントリ公開後から何度か修正し、テスト出来た Core 2 Duo 以降なら問題なくなっていると思われる。
Vista 以降となると Core 2 Duo 以降と判断してもいいだろうか?
OSアップグレードしている人はもう少し古い CPU の人もいそうだが、手持ちの環境などないのでこの辺りがテストできる限界かな。
Core 2 Duo 以前の環境でテストした人がいたら結果ください。

 FPUMMX3DNSSECMOVccE3DNEMMXSSE2TSCSSE3SSSE3SSE4.1SSE4.2SSE4aAVXAVX2FMA3AES
Intel Core 2 Duo U7500 1.06GHz ×× × ××××××
Intel Core 2 Duo U7600 1.20GHz ×× × ××××××
Intel Atom Z2760 1.80GHz ×× × ××××××
Intel Core i5 U470 1.33GHz ×× ×××××
Intel Core i7 920 2.67GHz ×× ×××××
Intel Core i7 930 2.80GHz ×× ×××××
Intel Atom Z3740 1.33GHz ×× ××××
Intel Core i7-2720QM 2.20GHz ×× ×××
Intel Core i7-3520M 2.90GHz ×× ×××
Intel Core i5-3317U 1.70GHz ×× ×××
AMD A10-5700 APU with Radeon ×× ×
Intel Core i7-4770T 2.5GHz ×× ×
Intel Core i7-5820K 3.3GHz ×× ×

ちなみに、私がテストした環境は以下。
Let's note CF-R7DW6AJR WinVista : Intel(R) Core(TM)2 Duo CPU U7600 @ 1.20GHz
Let's note CF-W7BC2AJS Win7 : Intel(R) Core(TM)2 Duo CPU U7500 @ 1.06GHz
ASUS Eee Slate EP121 Win7 : Intel(R) Core(TM) i5 CPU U 470 @ 1.33GHz
EPSON DIRECT Endeavor NJ5500E Win7 : Intel(R) Core(TM) i7-2720QM CPU @ 2.20GHz
ONKYO TW21A-B36C7B Win10 : Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz
Surface pro Win8.1 : Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz
デスクトップ Win8.1 : Intel(R) Core(TM) i7-4770T CPU @ 2.50GHz
acer Iconia W4 Win8 : Intel(R) Atom(TM) CPU Z3740 @ 1.33GHz
ASUS VivoTab Win8 : Intel(R) Atom(TM) CPU Z2760 @ 1.80GHz

投稿者 Takenori : 21:13

2016年01月07日

64bit 対応で必要な作業

必要な作業をざっくりまとめると以下のような内容、工数もおおよそ。

1. プロジェクトの設定と最小限ビルド通る状態 (済み)
2. プラグイン読み込みフォルダ変更 (済み)
3. SIMD 版 libjpeg から libjpeg-turbe への置き換え (1日未満)
4. グラフィック周りのアセンブリをイントリンシックで置き換え (1ヶ月)
5. Phase Vocoder をイントリンシックで置き換え (数日)
6. WAVE の 16bit float 変換がある部分のアセンブリをイントリンシックで置き換え (数日)
7. 例外発生時の CPU ダンプ周りの確認 (1日未満)
8. krmovie.dll の 64bit 対応 (数日)
9. wuvorbis のインラインアセンブリをイントリンシックで置き換え (1週間)
10. extrans のインラインアセンブリをイントリンシックで置き換え (数日)
11. その他プラグインの 64bit 対応 (数日~)
12. FPU 周り (1日未満)
13. ワーニングの確認 (数日)
14. 互換性のテスト

1. 通るようにした後、menu プラグインの対応も行った。
ポインタサイズの int 型 tjs_intptr_t と tjs_uintptr_t を追加したので、ポインタを整数に入れる場合はまずこの型にキャストする。
menu プラグイン対応で、いくつかのポインタの受け渡しで int 型へ変換されていたので、うまく動かなかった ( Windows.HWND/registerMessageReceiver など)。
tjs_intptr_t にキャストしてから Variant に入れるように修正してうまく動くように。

2. 64bit 版の場合 plugin64 フォルダからプラグインを読み込むようにして、32bit 版と共存できるようにする。
exe フォルダ、system フォルダ、plugin/plugin64 フォルダで読み込まれるので、両対応にするために plugin/plugin64 フォルダにのみプラグインを置くのを推奨することになる(両対応するのなら必須)。
そうしないと 64bit 版で 32bit プラグイン読んでしまって動かなかったりする。
前回同様 dev_64bit ブランチに入れた。

3. ライブラリの差し替えと、API が大きく違うのでそれに対応する。
libjpeg 互換 API もあるが、専用 API の方が速いようなので。

4. 一番作業量が多い。
簡易的に C へ変換するスクリプト書いたので、それにかけたのち細かいところ修正して MMX 版のソースコードを作り、可読性を考えたものへリファクタリング、その後 SSE2、AVX2 版を作る。
C 版から直接書き換えてもいいが、アセンブリ版から書き換えた方が効率が良さそう。
オリジナルと結果が異ならないようにテストコードを通して、随時確認している。
64bit 環境では、SSE2 が使える前提なので、MMX 版は不要。
確認するとイントリンシックで書いた MMX 版はだいぶ遅くなってしまう、SSE2 は期待するくらいの速度。
32bit 版で、MMX を残すかどうかは迷うところだけど、従来のアセンブリ版はおいておいていいかもしれない。
AVX2 は、使用頻度が高そうなもののみで問題ないか。
ブレンド処理で、PS系ではない通常の加算、減算、乗算、覆い焼き、比較(明)、比較(暗)、スクリーン乗算は、優先度低いと思われる。
アセンブリの MMX 版でもすべて実装されているわけではない。
AVX2 使うソースコードには、コンパイルオプションの指定を忘れずに。

5、6. は、アセンブリだけどCで書かれたオリジナルがありそう。
吉里吉里3に入っているものを少し書き換えることで対応できるかもしれない。
Phase Vocoder は優先度低いかも。

7. レジスタサイズなどが異なるので修正済みだが、正しい出力が出るかどうかは未確認。
出力確認の必要がある。

8. プロジェクトに 64bit 構成追加するのみで行けると思われるが、libogg,libtheora,libvorbis などで作業が必要かもしれない。
出力フォルダを bin/win64/plugin64 にする必要もある。

9. インラインアセンブラで SSE 対応など記述されているので、それを書き換える必要がある。
Ogg Vorbis 高速化プロジェクトから対応部分を持ってくることで対応可能かもしれないが、高速化プロジェクトは、別バイナリで対応する方式なので切り替え部分を作る必要がある。
64bit では Vorbis やめて opus に絞るのもありかもしれない。

10. インラインアセンブラで MMX 対応などされているので、それをイントリンシックに書き換える必要がある。

11. 基本的にプロジェクトに 64bit 構成を追加するのみだが、Win32 API 等一部修正が必要かもしれない。
出力フォルダを bin/win64/plugin64 にする必要もある。

12. 吉里吉里Z 64bit版試作で、FPU がどうこう書いたが、64bit 環境では FPU ではなく、SSE が使われるので、単純無効化で問題なさそう。

13. 64bit 化で大量にワーニングが出ているので、問題となるものがないか確認する。
例えば文字列長でポインタの end - start で求めた長さを int に入れる、size_t を int に入れるなどしているものがある。
問題とならないものは、キャストするなどワーニングを抑止し、問題が出そうな箇所については修正を入れる必要がある。

14. 対応完了後、32bit 版と同じように動くか確認し、問題があれば修正する。


その他
messenger プラグインで、32bit 版と 64bit 版で通信した時、64bit から 32bit へ送ると切り捨てが発生するのでその辺りのチェック。
Variant 型からポインタ変換している辺りで問題があるかも(ほとんどはint64にしてから入れているので大丈夫なはず…… menu プラグイン対応してみたらだいぶダメだった)。
Win32 API 周りで問題があるかも。

投稿者 Takenori : 02:55

吉里吉里Z 64bit(SSE2/AVX2)対応クラウドファンディング

合計金額 : 100万円

64bit化には他にも色々と必要な作業があるので、出資してくれる人を引き続き募集中です。
----------

目標金額 50万円以上

目標金額で実現することはアセンブリで記述されたグラフィック部分を SSE2/AVX2 を使った C++ に書き換えること。

64bit 対応で必要な作業で書いた中で一番作業量が多く、32bit版にも効果が大きいもの。
Core i以降であれば、SSE2 対応でグラフィックのブレンド処理などで局所的には2倍程度高速化、実使用環境でどの程度効果があるかは実装してみないことにはわからないが、ある程度の高速化が期待できる。
Haswell世代(ここ数年のCore i)以降であれば、AVX2 が使えるのでもう少し高速化が期待できる。
Core 2 Duo などの世代ではアライメントされていない場合のペナルティが大きいので少し効果が劣る。

目標金額を超えた分は、他の必要な作業に使います。


1万円単位で○万円出してもいいと言う人がいれば、メールを下さい。
人数分契約書を作って、開発するという方式を考えています。
1万円単位と書いたのは、事務手続きの関係からです。
あまりにも契約書を多く作るのは現実的ではないので。

契約書を作る関係で、住所と名前が必要なのでそれを私に明かしても良いという人限定です。
名前と住所についてですが、公開されるのは私個人のみにです。
公に公開されるのは、「コントリビューター項に載せる名前」で、匿名でも問題ありません。

メールには以下の内容を書いてください。
・住所と名前
・金額
・コントリビューター項に載せる名前/もしくは載せない
・支払い時期
契約書ひな型で問題ないか否か
・紙の契約書が必要かどうか(電子データでの契約書で問題ないか)
・税込/税別

メールアドレスはここに書いています。

支払いは前払いが好ましいですが、後払いでも可能です。
後払いの場合、完了月の翌月末までにお願いします。

テストは規模的に一人で全て網羅は難しいので、実装完了後公開しみんなに叩いてもらうことを想定しています。
もちろんテストは順次進めますが、安定性向上のためには多くの方の協力が必要になります。

形式的に受託開発となります(寄付(贈与)ではありません)。
内容が関連する方は確定申告にて経費として申告可能と思われます。
----
出してくれる人がいると言うことなので、合計金額を追記して、タイトルから「の需要」も省きました。

投稿者 Takenori : 18:42

吉里吉里Z 64bit対応 契約書ひな形

契約書のひな形を以下に。
紙で必要な方には紙で、電子データで問題ない方は電子データで送付します。
基本的に前回のVC対応と同じ内容です。
作業内容としては、最小限のグラフィック部分の書き換えのみ書いています。
金額が目標額を超えた場合は、その他の機能についても対応を行います。

2016/01/07
スケジュールの3月末にテスト期間が入っていなかったので、5月末へ変更。
2016/01/15
業務詳細に最低限対応するプラグイン明記
------
ソフトウェア開発業務委託契約書
貴方の名前(以下「甲」という)と私の名前(以下「乙」という)は、次の通り業務の委託をするにあたり、次の通り合意し、契約(以下「本契約」という)を締結する。

第1条(本件ソフトウェア)
本件により乙が開発するソフトウェアは以下の通りとする。
「吉里吉里Z 64bit 対応」

第2条(業務の範囲)
本件業務の内容は、以下の通りとする。
1. 業務概要
  吉里吉里Zを64bitでビルド、実行可能にする。
2. 業務詳細
・吉里吉里Zを64bitでビルド、実行可能にする。
・アセンブリで記述されたグラフィック部分をSSE2/AVX2のイントリンシックを使ったC++に置き換える。
・プラグインのextrans, krmovie, kropus, menu, wuvorbisを64bitでビルド、実行可能にする。
・その他64bit対応機能、詳細仕様及び設計詳細は乙に一任する。
3.スケジュール及び納品
・作業スケジュール
自 2016年1月15日 至 2016年5月31日
・納品
吉里吉里Zと同一ライセンス(修正BSDライセンス)でソースコードをGitHubの吉里吉里Zリポジトリへコミットする。
実行バイナリコードを一般に公開し2カ月間のテスト期間経過後納品完了とする。
納品は上記スケジュールより前倒しでも可能とする。

第3条(対価及び支払条件)
1. 甲は乙に対して本業務の対価として金○○円也(消費税込)を以下の通りに支払う。
2. 甲は、本業務の対価を、○月末日までに乙の指定する銀行口座に振り込むことにより乙に支払う。

第4条(瑕疵担保責任について)
本契約に基づき作成されたプログラム等に瑕疵があった場合、乙は、公開後6カ月間のみ修正を受け付け、その後の修正は任意の対応とする。

第5条(著作権並びに著作人格権について)
本契約に基づき乙が作成し提供するプログラム等の権利(著作権法第21条から第28条に定めるすべての権利を含みます)はそのまま乙に属するものとする。ただし、乙は、その成果物を最終的に「修正BSDライセンス」で、甲および「吉里吉里Zプロジェクト」及びそれを利用する第三者に対して提供するものとする。

第6条(協議)
本契約締結後に記載内容に変更が生じた場合は、甲、乙協議の上、書面により別に定めるものとする。
本契約に定めのない事項又は本契約の内容等に疑義が生じた場合には、その都度、甲、乙双方が民法をはじめとする法令等を踏まえ、誠意をもって協議する。

本契約の成立を証するため、本契約書二通を作成し、甲乙記名捺印の上、各自一通を所持する

平成28年○月○日

甲: ○○
乙: ○○

投稿者 Takenori : 20:04

2016年01月20日

64bit対応作業の予定

64bit 対応は、64bit 版のみになるのではなく、32bit 版と 64bit 版の2つのバージョンが同時にリリースされることになる。
32bit 版はほぼ今まで通りだけど、SSE2/AVX2 対応による描画周りの高速化が期待できる。
また、イントリンシック+テンプレートと言う構造になる予定なので、バリエーションの展開がしやすくなるため従来拡大縮小やアフィン変換などでブレンドモードが限定されていたものが、operateRect と同じようにブレンドモード対応しやすくなる( (現バージョンでは未実装です)と書かれていた部分が実装しやすくなる )。
この部分も今回対応予定だけど、スケジュールによっては今回は見送る可能性もある。
他に対応できるかどうかと言うものに、通常のアルファ合成以外での destination alpha を考慮した合成がある。
アルファを持つ画像2つを合成した時に、出力にもアルファが求められる時、通常の合成とは異なり destination alpha も考慮する必要があり、この合成は現在通常のアルファ合成のみでサポートされている。
通常のアルファ合成であれば式の変形で簡略化できるが、加算合成などでは式が複雑になる。

拡大縮小やアフィン変換でのブレンドサポートと destination alpha を考慮したブレンドを現在やろうとしたら一時レイヤーへ描き出したりする必要があるので、これが実現できるとその分ショートカット出来て高速化が期待できる。

libjpeg の置き換えも 32bit 版に影響するが、速くなるか遅くなるかは置き換えてみないことには何とも言えない。
今使用している SIMD 版 libjpeg は 32bit 版のみなので、64bit では使えないため libjpeg-turbe に変更する。
大幅な速度変化はないと思われるが、やってみないとわからないところ。

その他は 32bit の各種機能で 64bit 対応する必要がある箇所の対応。
プラグインは extrans, krmovie, kropus, menu, wuvorbis を対応する予定。
64bit 対応で必要な作業で書いている extrans, krmovie, wuvorbis 以外はほとんどプロジェクトの設定追加してビルドしていくのみと思われるが、menu 対応でいくつか修正の必要があったので、その都度対応が必要になる箇所もある。
対応が必要なケースはいくつか対応しているうちに類型化出来るはず。
その他 KAGParser などについては時間次第。
単純な細かい作業なので、一気に対応してしまわなくても、今後順次対応していける。


スケジュール

3月末 64bit対応版テスト公開し色々な人に確認してもらいつつテスト
5月末 64bit対応版正式リリース

上記のように書いているが、64bit対応は一気に書き換えると言う性質のものではないので、バイナリ公開は適時行う予定。
まずは、SSE2 対応を進める途中段階で何度かリリースして、高速化などを実感してもらいたい(期待したほどではないかもしれないが)。
プラグイン( extrans, krmovie, kropus, menu, wuvorbis )については1個ずつ対応していくので、これも順次公開。
その他の作業についても、関連性が低いので順次公開していく。

SSE2/AVX2 対応部分以外は 32bit 版には関係薄いので、興味も少ないかもしれない。

投稿者 Takenori : 22:48

2016年01月21日

MMX サポートを残すかどうか

SSE2 は Pentium 4 以降で使えるので、それ以降の CPU であれば使える。
MMX を残すかどうかは、Pentium III 世代がまだ使われているかとだいたい同じ。
XP や Vista、7 がいつ登場したかを見ると以下のような感じ。

Windows XP 2001年~
Windows Vista 2006年~
Windows 7 2009年~

CPU の方は、こんな感じ。

Pentium 4 2000年~
Pentium M 2003年~
Core 2 (Duo/Solo) 2006年~
Core i(3/5/7) 2008年~
Atom 2008年~

XP 以降サポートであれば MMX を切ってしまうのはまだ時期尚早、Vista 以降サポートなら大丈夫か。

32bit 版では現在のアセンブリでの MMX サポートを一応残しておこうかと思っていたけど、なくしてしまってもいいかもしれない。
残すとなると、最終出力されるバイナリサイズが少し増えるのと、ビルド時間が少し伸びるくらい。
バイナリサイズがどれくらい増えるか見て判断と考えていたけど、ビルド時間の方は少し気になるか。
本体のアセンブリをなくして nasm 依存をなくしても、libjpeg(SIMD) で使っているから結局ビルドには nasm 必要で、nasm 依存はなくせないからその部分は一緒。

64bit 版では MMX サポートはなくしてしまう。
64bit(AMD64) 環境では SSE2 は必須で、必ず使えることが分かっているからと言うのと、アセンブリの書き換えが必要となるので追加で作業が増えるため残す意味はほとんどない。

投稿者 Takenori : 23:19

2016年01月28日

ブレンド処理のSSE2化版

ブレンド処理のSSE2化版
krkrz20150127.zip

PS系の重いブレンド処理は高速化しているのがよくわかるが、シンプルなアルファブレンドなどは効果が薄い。
ブレンド処理の部分についても順次SSE2化していく。
次はユニバーサルトランジションなどが効果を実感しやすいだろうか。

投稿者 Takenori : 00:40

2016年01月30日

32bit版と64bit版のプラグイン

ゲームではまだしばらくの間 32bit 版でも全然問題ないと思われるので、あまり関係ない話。
将来的に 64bit 版対応が必要になった時のために気に留めておくだけでいいと思う。
ツール用途などで 64bit 版対応にリリース後即座に取り掛かる場合は関係ある話。
とは言っても、インストーラーで OS を見て、32bit 版か 64bit 版のどちらを入れるか判断して片方しかインストールしないようにするのであれば、それほど関係ないが、64bit 版はプラグインフォルダ名が変更になっているのでそこは関係ある。

32bit 版と 64bit 版では、それぞれ用にビルドしたプラグインが必要になる。
32bit 版は今まで通りなので従来のものがそのまま使えるが、64bit 版は 64bit 用にビルドの必要がある。

それぞれ対応したプラグインを読み込む必要があるが、同じ名前にして同一フォルダにプラグインを置くことは出来ないので、読み分けのための何らかの方法が必要になる。
今回は、32bit 版は従来通りにして、64bit 版については plugin64 フォルダから読むようにした。
exe フォルダ、その下の system フォルダから読むのは変わっていないので、プラグインはそれぞれ plugin/plugin64 フォルダに分けて入れることが今後推奨される。
従来のようにその他のフォルダに 32bit 版 dll を置いた状態で 64bit 版 exe を起動するとエラーになると予想される(実際の挙動はまだテストしていない)。

両方のバージョンの exe を混在させて配布すると言うのは、zip で配布するゲーム用途の方が多そうなので、このような対処が必要かはわからないが、回避できるように対策を入れておく。

投稿者 Takenori : 19:04

2016年03月28日

画像ヘッダー読み込みと画像読み込みのプラグイン化

・画像本体は読まずにサイズ等だけ得たい
・SUSIE プラグインではなく、本体の画像読み込みと同じような動作で読みこむプラグインが欲しい

これら2つに対応した。
64bit 化以降のリリースバージョンで使えるようになる。

ヘッダーは、
var dic = Bitmap.loadHeader( "filename.ext" );
と言う形で呼び出すと取得できる。
Bitmap クラスのスタティックメソッドとして実装されている。
Layer にはないので注意。
返される辞書に width, height は必須でその他要素は画像フォーマットごとに異なる。
渡すファイル名に拡張子は必須。
通常の読み込みメソッドと同様に拡張子で種類を識別するようになっている。

プラグインから TVPRegisterGraphicLoadingHandler/TVPUnregisterGraphicLoadingHandler で読み込み関数等を登録できるようにした。
登録するのは、拡張子、読み込み関数、ヘッダー読み込み関数、保存関数、保存可否とオプション取得関数、フォーマットポインタの6つ。
読み込み関数は本体とほぼ同じ形で読み込むもの ( IStream になっているという違いはある )
ヘッダー読み込み関数、保存関数は、そのままの意味。
ただし、保存は Bitmap.save の meta にオプションを渡せるようになっている ( 引数名は meta から option に変更予定 )。
Layer.saveLayerImage は、オプションを渡せないので注意。
保存可否とオプション取得関数は、指定した形式で保存できるかどうかの判定と、保存できる場合に指定可能なオプションを返す。
指定可能なオプションは画像フォーマットごとに色々と異なるので、別途取得する形となっている。
var dic = Bitmap.getSaveOption("type"); と言う形で呼び出す。
type は Bitmap.save/Layer.saveLayerImage に渡すものと同じ。
返される辞書には、オプションで指定可能なキーが入っていて、キーの内容(辞書)が指定する値の意味。
各キーの辞書には type として形式が入っていて、range, select, select text, boolean, integer がある。
range の場合、min と max があって、その値の範囲で値を指定可能。
select は、items があって、その配列の要素の index を指定可能。
select text は、items があって、その配列の要素のいずれかの文字列を指定可能。
boolean は、true/false が指定可能。
integer は、整数値が指定可能。
その他に desc に説明が、default に既定値が入っている。

フォーマットポインタは、クラスを使って作りたい等の時に登録する。
登録する各関数の最初の引数に登録したフォーマットポインタが入って呼び出される。
NULL でも問題ない。

保存は必須ではないので、保存関数と保存可否とオプション取得関数を NULL にして登録すれば、その形式で保存できないが読み込みは出来るプラグインが作れる。
プラグインのサンプルとして、wic フォルダに Windows Imaging Component (WIC) を使って画像の読み書きを行うプラグインが入っている。
このプラグインを読み込むと GIF/ICO/TIFF の読み込みと、TIFF の書き出しに対応する。

画像読み込み/保存がプラグイン化されたことで、将来的に SUSIE プラグインは本体からプラグインへ移動される予定。
SUSIE プラグインプラグインとややこしい名前になるが。

投稿者 Takenori : 17:35

savedata フォルダが必要な時だけ作られるように

昔の吉里吉里2 は savedata フォルダが常に作られるのではなく、必要になった時に作られていたと記憶しているが、いつのころからか常に作られるようになっていた。
Revision 2612 の変更で常に作られるようになったようだ。
必要のない時は作られない方がいいだろうと言うことで、常時作られる動作ではなくした。
作られるのはログ書き出し時や TJS2 での saveStruct 呼び出して書き出した時(セーブ時)。
起動しただけで作られてしまうのは、少し気持ち悪いのでこの昔の(?)動作とした。
64bit 化以降のリリースバージョンでこの動作となる。

吉里吉里2 のログ見る限りでは、必要になった時だけ作るのが意図した動作で、常時作られるのは意図していないものと推測されるが、何か問題があって常時作られるようにしたのだろうか?
常時作られなければ問題が発生するケースを知っている人がいたら教えてもらえると助かります。

投稿者 Takenori : 17:53

2016年04月03日

krmovie を本体に統合

krmovie.dll を本体へ統合した。
64bit 化以降は krmovie.dll が不要になる(本体に入っている)。
krmovie.dll が分離していたのは C++Builder でなぜかうまくビルドできなかったかららしい(Deeさんが言ってた記憶)。
つまりは歴史的経緯によるもので、本体にくっついていても何ら問題ない。
実際問題として、krmovie.dll と本体は一体的に使う前提で、差し替えたりすることは出来ず、VideoOverlay クラスで動画を再生するのなら必須。
また、インターフェイスの関係上 krmovie.dll と本体のバージョンが一致していなければ、実行時エラーになる。
krmovie の機能追加等を色々とやってきたけど、分離していたために両方に修正入れたりして色々と面倒が多かったので、出来れば一緒にしてしまいたいと常々思っていた。
今後 mixer モードで再生した時にそのムービーテクスチャを DrawDevice に渡して描画するなどの機能を実現するに当たり、本体にあった方が都合が良いからと言うのもある。

と言うことで、今後は krmovie.dll は配布物に添付されていないけど、本体に機能は入っているから気にしなくても良い。

本体に統合されると色々な Codec をサポートすると肥大化していくため、他の Codec をサポートできるように動画フォーマットプラグインにも対応した。
このプラグイン化で theora が独立したプラグインとなった。
その他の形式は OS に入っている Codec で再生するためバイナリサイズの増加は小さいが、theora は独立した Codec のため増分が大きいのと、そこを境界にするとわかりやすいと言うことから分離した。

動画もプラグインに対応したことで、前回書いた画像も合わせて主要形式はプラグインによってフォーマットを拡張できることになった。
今後は、音声・画像・動画をプラグインによってサポートするフォーマットを増やすことが出来る。

投稿者 Takenori : 22:49

吉里吉里Z に欠けているドキュメントを GitHub に

吉里吉里Zのページには API リファレンスなどが置かれているが、ドキュメントは圧倒的に不足している状態。
そこで GitHub にリポジトリを作って、Markdown で書いて、みんなに PullRequest してもらってドキュメントのカバー率を上げようと思い、吉里吉里Z 情報 を作った。

今のところ体系立てて整備するのではなく、あった方が良さそうなドキュメントをどんどん追加してもらってカバー率を上げ、後でインデックスの整備や編集を行って見やすさを改善する方針。
まずは検索でヒットすれば何とかなるだろうと。
もちろん体系立てて書かれたドキュメントを一気に PullRequest してもらっても良い。

私の場合ブログに開発しつつその仕様など上げているが、Fix した仕様かどうかなど曖昧な部分もあるため、ブログの中から固まっているものなど順次追加していく予定。
また、各機能のテスト用に書いたスクリプトは、ほぼそのままその機能の使い方サンプルともなるので、そのようなものも追加していく。

吉里吉里Zのページ自体も GitHub Pages なので PullRequest なども出来るんだけど、まずは独立して追加しやすいものがあるといいだろうと言うことで。

投稿者 Takenori : 23:14

2016年04月05日

吉里吉里Z 64bit対応β1公開

吉里吉里Z 1.3 β1

確認をお願いします。
64bit版だけでなく、32bit版にも主にグラフィック部分に修正が入っています。
不具合を見付けたら TwitterGitHub 等で連絡ください。


64bit 対応以外にグラフィック部分がアセンブリMMXからSSE2/AVX2イントリンシックで書き換えられ、従来よりも高速化しています。
添付しているもの以外のプラグインを 64bit 対応する場合は、dev_64bit ブランチをチェックアウトして、その中の tp_stub.h/.cpp を使用してビルドしてください。
64bit 版プラグインは plugin64 フォルダに入れてください。
また、プルリクエストは dev_64bit へ行ってください。


拡大縮小フィルタいろいろ で書いた各種フィルタが追加されています。
stNearest, stFastLinear は従来通りですが、SSE2 対応されたことで速くなっているものもあります。
stLinear, stCubic は従来から大きくアルゴリズムが変更され、高速化されています。
stSemiFastLinear, stFastCubic, stLanczos2, stFastLanczos2, stLanczos3, stFastLanczos3, stSpline16, stFastSpline16, stSpline36, stFastSpline36, stAreaAvg, stFastAreaAvg, stGaussian, stFastGaussian, stBlackmanSinc, stFastBlackmanSinc が新規追加され、従来より高画質な拡大縮小が可能です。
なお、上記フィルタは拡大縮小のみでアフィン変換では未実装です。
また、stNearest, stFastLinear を除くフィルタではブレンド処理も同時に行えるようになっています。

画像ヘッダー読み込みと画像読み込みのプラグイン化 が行われています。


今後の予定
4月末までは64bit版不具合対応とともに issues にある過去不具合等で対応できそうなものに対応。
5月末に正式版リリース予定。


更新内容一覧
64bit版を追加
アセンブリで記述されていたグラフィック部分をMMXからSSE2にしたイントリンシックで書き換え
グラフィック処理の一部にAVX2を使うものを追加
拡大縮小フィルタを追加
JPEG XRをWindows Imaging Componentを使用して読み込むように変更
JPEG XRの書き出しを追加
krmovie.dllを本体に統合
theoraをプラグインに分離
動画プラグインに対応
画像プラグインに対応 #101
画像ヘッダー読み込み機能を追加 #99
savedataフォルダを必要な時に作られるように修正 #204
フルスクリーン時の画面回転・解像度変更で描画位置がずれる問題を修正 #98
メインループの条件からWindow数を削除 #174
レイヤーのタッチキャプチャー追加 #138
BasicDrawDeviceでDestRect指定された時にBackBufferサイズより大きい時一度破棄して作り直すように修正 #135
バックバッファのサイズをウィンドウのあるディスプレイの最大サイズかクライアント領域の大きい方を使うように修正 #201
ウィンドウ最大サイズが0(初期値)の時、INT_MAXまで拡大可能なように修正 #203
タッチ機能のデフォルト動作指定に対応 #196
FreeTypeを2.6.3に変更
SIMD libjpegからlibjpeg-turboに変更
Window.showModalでフォーカスが得られてないことになる一連の不具合修正 #178, #114, #112
FreeTypeでブラーが機能していなかったので修正 #177
アスペクト比の異なる画面でのフルスクリーン時Layer.cursorX/cursorYが間違った値を返していたのを修正 #191
テンポラリファイル生成にDELETE_ON_CLOSEをつけるようにして強制終了してもファイルが削除れるように修正 #110
TVPGetPlatformNameで返す文字列を定数ではなく、Win32上かWin64上か判定して返すように修正
sprintfで大きい整数が正しく処理されていなかったのを修正 #184
Array/Dictionary.loadStructを追加
ライセンス文取得時にバッファオーバランが発生することがあったのを修正 #180
adjustGamma の処理結果が吉里吉里2と異なっていたのを修正 #194

投稿者 Takenori : 03:22

2016年04月19日

DrawDevice の変更予告

今回の64bit化で~と言うことではなく、もう少し先の話。
たまにツイッターで言っていたりするが、ここでまとめて、何か問題がありそうなら教えてくださいと言うことで。
予定しているは以下。

1. 動画との連携インターフェイスの追加
2. Bitmap 内部構造の正順化
(3. DirectX11 化)

1. 動画との連携インターフェイスの追加
ミキサーモード( VMR9 )で DrawDevice と連携し、任意のサーフェイス( Texture )に描画できるようにする予定。
現在のミキサーモードは、子ウィンドウを作ってそこで Direct3D を使い描画しているが、本体も同じように Direct3D で描画していると重複していて無駄なこと、現在の形ではミキサーモードで動画の手前に描画できないので、これを解消する目的で DrawDevice と連携するインターフェイスを追加します。
描画を DrawDevice に任せる利点として、動画の手前に任意のレイヤー等を描画可能にできることです(無駄を省くのはおまけ)。
現在オーバーレイモードは問題が発生しやすいため非推奨かつ KAG3 ではミキサーモードに振り替えられているため、ミキサーモードが標準ですが、ミキサーモードとオーバーレイモードは、実質的に最前面で動画を再生する仕組みで、その手前に何かを描画することが出来なくなっています。
VMR9 は、サーフェイス( Texture ) に動画を描画する仕組みで、別に最前面固定ではありません。
これを活かすために DrawDevice と連携するようにします。
Layer Tree Ownerによって、レイヤーが必ず Window に属さなければならない制約はなくなっており、BitmapLayerTreeOwner によって、任意の Bitmap にレイヤーをぶら下げる機能が入っていますが、これを DrawDevice の Texture に拡張することで、複数のレイヤーツリーを持てるようにすれば、動画の手前にレイヤーを置けるように出来ます。
これは Window の中に Window を持てるような感覚です。
動画の手前にレイヤーを描画できない現在の制約は、ダイアログやメニュー等をレイヤー化しようとした時問題となります。

MediaFundation の EVR 描画でも連携を追加する時再度インターフェイスが追加される可能性もあります。
MediaFundation も DirectShow 同様ややこしいので実装に時間がかかることが予想されるため、やるとしても先の予定。


2. Bitmap 内部構造の正順化
吉里吉里2/Z では、Bitmap が上下逆順で格納されているが、これを正順化する予定。
正順を要求するライブラリとの連携やマルチプラットフォーム化を考えると、逆順なのは足かせとなるので。
上下逆なのは、昔の制約で今となっては不要なもの。
上下依存しないようにきちんと実装していれば問題は出ないが、BasicDrawDevice では問題が起きたので、他の DrawDevice でも問題となる可能性があります。
後、内部的に動画のレイヤーモードも反転して描画されるので、その部分も修正が入る。


3. DirectX11 化
DirectX9 で問題が出るケースを見かけたりするため、Vista 以降だと DirectX11 が使えるので切り替え予定。
ただ、VMR9 は DirectX9 のサーフェイスを要求するので、難しい可能性もある。
変換して受け渡しできるはずだけど。
MediaFundation の方は DirectX11 と連携するには Windows8 以降と言う制約があるので、こちらはこちらで別の問題がある。

投稿者 Takenori : 17:50

2016年04月24日

吉里吉里Z本体に9 patch ( 9 slice )を入れるか検討する

Android、iOS、Flash、Unity、Cocos2dx などで使われている UI の背景などを描画する機能(仕様)。

角の4隅は等倍でコピーして、上下左右の4辺はそれぞれ横or縦に拡大、真ん中の領域は拡大することで、伸縮可能な画像を作る。
下図を見てもらうとどこがどのように拡大されるのかわかりやすいはず。
ninepatch_20160424.png

実際にやるとどうなるかは下のような角丸四角がわかりやすい。
toast_frame.9.png
CC BY 2.5によってライセンスされた Android のリソースデータです。 Copyright (c) 2005-2011, The Android Open Source Project

拡大するとこんな感じ
round_rect_20160424.png

四隅や辺が維持されているので、拡大しても荒れない。

このメリットは――
1. 任意のサイズに見た目の劣化なく拡大できる(制約はあるものの)
2. メモリ、ストレージの節約
3. 再利用しやすくなる
4. 見た目のデザインとレイアウトを分離できる
5. ベクター描画よりは軽量

1.
制約としては
・拡大される部分は単一色もしくはグラデーションであれば劣化しない。
・元画像のサイズより小さくは出来ない。
の2つ。
それをクリアすれば、色々なサイズに使用できる。
サイズが変えられると言うことは、アニメーションもさせられる。
9patch_20140424.gif

2.
メモリの節約は吉里吉里ではあまり意味がない。
レイヤーに描画した時に描画後サイズが持たれるので、メモリは節約にならない。
ストレージは節約されるが、PC では多少画像が大きくなってもさほど問題とはならない。
と言うことで、節約と言う意味では効果は薄い。

CPU 描画系ではなく、GPU で描画する時テクスチャ面積を大きく節約できるメリットがある。
その場合は、四隅は反転、四辺も反転することでより節約できるが、9patch では少し無駄がある。
とは言っても、反転するとある程度想定できるので、画像を比較して機械的に変換できるので、変換してしまえばその無駄もなくせる。
ストレージは、PC ではなく容量にシビアな環境では効いてくる。

3.
UI ウィジェットを準備したら、後は各パーツの画像の差し替えで見た目を変えられるが、9patch があれば背景等のサイズが可変になるので使いまわしやすい(個々のウィジェットに合わせて画像を準備する必要がない)。
スキンとして、パーツ画像セットを準備すれば、その画像セットを差し替えることで UI の見た目をゲームごとに調整できる。

4.
UI ウィジェットの見た目のデザインとレイアウトを分業できる。
レイアウトはツールがないと面倒なので、将来的には配置用のツールが欲しいところ。

5.
基本的には単純なコピーと拡大なのでベクター画像のような複雑な処理は要らない。

以上のように便利でツール用途でもゲーム用途でも使えるので本体に組み込もうと思っていたのだが、プラグインでいいんじゃないか?と反対されて少し検討し、本エントリーを書く。

問題は――
・画像自体ではなく画像の使い方に意味を持たせて処理すること、プリミティブな機能ではなく複合的な機能であることを懸念
・汎用性に懐疑的(うちは使わないので)
と言ったところのよう。
同種の機能としてはカラーキーがある。
今ではほとんど使われなくなったが、使い方に意味を持たせて処理している。

9 patch の汎用性については、今のところ吉里吉里Zに実装自体されていないので使われていないけれど、実装されツールも整備すれば普通に使われる機能になると思われる(他環境での使われ方からしても)。

と言うことで、やっぱり本体に組み込んでしまっていいんじゃないかと思った。

投稿者 Takenori : 23:13

2016年04月28日

部分的マルチプラットフォーム化による段階的移行

一気にやるのは難しいから、部分的に下位部分を変更して行って、その内マルチプラットフォームになっている作戦。
一気にやる場合でもどこをどのように変更すべきかについてまとめておいた方が良いと言うことで。
必要とわかっているものを列挙する(他にもある可能性あり)。

1. サウンド
2. ウィンドウシステム(グラフィックAPI)
3. 動画
4. メインスレッドへの処理委譲
5. タイマー
6. スレッド
7. アトミックAPI
8. プラグイン
9. 環境固有情報
10. ファイルシステム
11. 文字列処理関数
12. メッセージリソース
13. システムカラー
14. IME
15. マウスカーソル
16. クリップボード
17. フォント

使用するライブラリに関係して Windows、Linux+MacOSX、Android、(iOS) と言う順になりそうだが、気持ち的には、Windows、Android、MacOSX、Linux、(iOS) なので、どの環境が二番目に動くようになるかは不確定。

1. サウンド
現在 DirectSound が使われているが、少し古いのでマルチプラットフォーム対応のライブラリで新しい API にも対応できると良い。
OpenAL が有名だが、BSD → LGPL → プロプラエタリ or OpenAL soft(LGPL) と使いづらい変遷をたどっている。
他には PortAudio がある。
PortAudio に対応すれば、少し新しい WASAPI をサポートできる。
Windows/OSX/Linux 対応で MIT License 。
Android/iOS 対応はないが、マルチプラットフォームに対応されていて抽象化されているだろうから、インプリメントしやすい可能性が高い。
iOS は、Core Audio で OSX と共通で使えるかもしれない。
Android は、OpenSL で別実装の必要があるはず。
マルチプラットフォームためだけでなく、Windows でも新 API サポートと言うことでメリットがある。
XAudio2 もサポートできるとより良いが。

2. ウィンドウシステム(グラフィックAPI)
マルチプラットフォームなウィジェットライブラリは色々とあるが、吉里吉里Z で使うには大きすぎる。
吉里吉里Z だと、ほとんどウィンドウの表示くらいが出来ればよく、ボタン等のGUI部品ウィジェットは不要。
マルチプラットフォームのGUIツールキット で以前書いた通り。
GLFW は Window+OpenGL 周りのライブラリ。
Windows/OSX/Linux 対応で zlib/libpng license.
Android/iOS 対応はない。Android は NativeActivity ではなく Java の Activity で実装してから C 側を呼び出す実装の方が色々と対応しやすい。
OpenGL なので、その部分に関しては全プラットフォーム共通となる。
Windows では、現在の win32 API を直接叩き Direct3D で描画するものがメインで、GLFW 版 Window の扱いをどうするか検討の余地がある。
マルチプラットフォームとなると OpenGL が標準的だが、Windows では DirectX の方が都合が良い。
デバッグオプションとして ifdef で切り替えるか、動的にも切り替えられるかだが、動的に切り替える用途も特にないのでデバッグオプションで切り替えてしまって良さそう。
ウィンドウは TTVPWindowForm を抽象化して、WindowImpl は共通化してマルチ展開するのが楽(羽々斬(吉里吉里Java)でもそのように実装)。
DrawDevice 用などに iTVPWindow と言うインターフェイスも存在しているので、インターフェイス名をよく考えないと紛らわしくなる。
また、DrawDevice の変更予告 で書いた Bitmap 上下反転解消は先に欲しい。

3. 動画
各環境固有で実装。
環境ごとの API を使いハードウェア支援を受けて再生出来ないと負荷が厳しい。
抽象化層を作り、汎用的な API を切り出してライブラリ化出来ると再利用性が高くなるが、吉里吉里Z 専用で作ってしまうのが早い。
実装に時間がかかるので、今ある Windows 以外は後回しか。

4. メインスレッドへの処理委譲
NativeEventQueue にてある程度抽象化して実装しているが、機能自体は Win32 のメッセージ機構を用いて実現されている。
他環境では自前で排他キューを準備して、キューに入ったらメインスレッド起こして読んでもらうなどの実装が必要。
GLFW では、null イベント投げて起こす機能があるので、そこでキューを読んで処理すると実現できると思われる。
ロック機構は環境固有となるので、抽象化された API 等を作り、それ経由で呼び出すことになる。

5. タイマー
内部で使われる Win32 のタイマーを使ったメインスレッドでタイマーを呼び出すためのクラスと、TJS2 のタイマーがある。
TJS2 のタイマーはスレッドを使用した自前実装で環境非依存(ただし、スレッドとメインスレッド実行が環境依存あり)。
スレッドでタイマー計測し、メインスレッド呼び出しを行う。
TJS2 のタイマー実装(自前実装)に統一し、内部用か TJS2 用かを振り分けて処理するようにするのが良さそう。

6. スレッド
Windows 以外は pthread だが、POCO で実装すると共通化出来る。
C++1xで追加されたスレッドでもいいが、POCO の方が扱いやすそうに見える。
Windows は現在の実装でも、POCO の実装でもどちらでもよい。
動作に問題ないようなら POCO で統一してしまった方が後々楽。
グラフィック描画で使われているスレッドプールをどうするかと言う問題がある。
問題は CPUアフィニティ。
Android ではスレッドとコアの対応付けが期待したように動かないらしい。
Windows は現在の実装として、他の環境はアフィニティは諦めてしまっても良いか。
スレッドプールでは、アトミックAPIが使われているので、これは抽象化した方が良い。
当然ロックやイベントなども必要。
ロック機構が TJS2 側で実装されているのがやや難。
TJS2 が POCO 依存してしまうのは諦めるか、ifdef で pthead か Win32 で切り替える方法があるが、POCO 依存にしてしまうのが妥当か。

7. アトミックAPI
Windows では Interlock 系のメソッド。
単純に環境ごとに切り替える定義で問題なさそう。
tjsConfig などに追加するのが無難か。

8. プラグイン
Windows 以外は、共通の API でいける。
ifdef で環境ごとに呼ぶ API 切り替えてしまって良さそう。
iOS はそもそも dll が使えないのでサポートできない。
本体ではなく、プラグイン側に提供する tp_stub も環境依存しているので、そちらへ提供する API なども環境依存をなくすか、環境ごとに tp_stub を吐き出す必要がある。
どちらが良いかは迷うところ。

9. 環境固有情報
OS 名やフォルダなどの環境固有情報は、POCO を使用して取得する。
Windows は現在のままの実装か結果が変わらないものについては POCO に任せて共通部分を多くした方が良さそう。
どちらにしても一段ラッパーをかませて抽象化する。

10. ファイルシステム
Windows は、Win32 API で その他は FILE ポインタを使った標準的なファイル入出力。
API を抽象化して実装できるとよい。
Windows は、UTF-16 だが その他環境では UTF-8 になるので、Windows 以外は変換が必要。
また、Linux/Android はケースセンシティブなので、ファイル検索時などに見付からない場合、大文字小文字無視した比較で検索するなどの必要がある。
パスデリミタも¥と/の違いがある。

11. 文字列処理関数
wchar_t のバイトサイズが Windows では 2バイトだが、Linux 系は 4バイト。
tjs_char を 2バイト固定にしてしまい、各文字列処理関数を自前で持ってしまうのが問題が少ないと思われる。
また、文字列処理も SIMD 化可能なので、SIMD 実行も行えば高速化が期待できる。
実装は、Android の標準ライブラリの Bionic libc が BSD ライセンスなので、そちらを tjs_char に書き換えて使用するのが良いか。

12. メッセージリソース
環境ごとにリソースに埋め込むのが理想だが、ソースコードにメッセージを埋め込む形でも問題はない。
初期は Windows のみリソースに持ち、他は各環境のリソースに順次置き換えてくのが現実的か。
Android は、ロケールは Java を経由して取得する必要がある。

13. システムカラー
Windows での標準的な色を定数として返すか、テーマカラーシステムようなものを追加して、任意の定義ファイルから読み込めるか。初期は定数で十分。

14. IME
Windows 以外は非サポートか、環境ごとに実装するか、Wnn などを組み込んで自前でやるか。
PC 以外ではソフトウェアキーボードも必要になってくるが、それらは TJS2/Layer での実装も可能、変換さえできれば何とかなる。

15. マウスカーソル
環境ごとに実装が必要。
Android は変更できない。
初期は、Null Device で単に何も起こらない実装でよい。

16. クリップボード
環境ごとに実装。
初期は、Null Device で単に何も起こらない実装でよい。

17. フォント
現在 GDI と FreeType が使えるが、Windows 以外では FreeType 限定。
元々マルチプラットフォームを見越して実装していたもので、役立つ時。
Font.rasterizer は Windows 以外では意味がなくなる。
システムにインストールされているフォントの取得は環境依存となるが、全て対応していくのは大変だからまずはフォントファイルのみの対応。
Font.faceAsFileName などのオプションを追加して、このオプションが有効な時は face で指定された文字列はファイル名として扱ってフォントファイルを読み込む。
カンマ指定で複数スタイル(bold等)のファイルを読み込めるとより良い。
読み込まれるのはファイルの最初に合致する face。
Windows 以外は、Font.faceAsFileName は常に true (将来システムのフォントを引っ張って来れるよう実装したら、Windows と同じように false デフォルトとなる可能性あり)。
デフォルトのフォントはリソースやオプションで指定可能だが、Windows 以外では今あるフリーフォントを考えると Noto Sans CJK が妥当か。
Windows と同じように指定可能として。
互換性を考えるのならスクリプトの最初に――
Font.rasterizer = frFreeType;
Font.faceAsFileName = true;
――と指定する。
また、アーカイブには Noto Sans CJK の日本語フォントを入れる。


Null device
吉里吉里2 は Intf で共通 TJS2 関数を実装、Impl で環境固有 TJS2 関数を実装する形になっているが、TJS2 からは出来るだけ共通の関数が使用できることが望ましいため、TJS2 に公開するクラス/関数レベルでの抽象化ではなく、より下位の部分で C++ で抽象化する方が作りやすい。
C++ の抽象化されたクラスは、スタブや Null device と呼ばれる何もしないインスタンス化できるクラスを実装し、そのクラスを元に各環境用に実装をすると複数環境で実装しやすい。

抽象化されたマルチプラットフォーム API 群を整備し、基本的にはそちらを使うような実装へ変えていく。
それら API はドキュメントも整備されている方が望ましい。


64bit 版では、上記以外のもので一部マルチプラットフォーム対応になったものがある。
ShiftJIS UTF-16 変換を Win32 API から内部関数へ変更し、非 Windows 環境でも変換に差が出ないようになった。
SIMD 版 libjpeg を turbo jpeg へ変更し、PC(x86) のみでなく ARM でも SIMD 対応された libjpeg が使えることになった。


変更の優先順位は、現行の Windows 版でも意味のあるものから順に対応して、優先度が低いものは Null Device で対応。

第一は、Windows に恩恵があるサウンドと文字列処理のみ。
第二は、Windows 版にも変更が入るもの タイマー、スレッド、アトミックAPI、環境固有情報、ファイルシステム。
第三は、Windows 版では使われないが、Windows でも確認できるもの ウィンドウシステム、メインスレッドへの処理委譲、メッセージリソース、システムカラー。
第四は、Windows 版では使われないし、他環境用での確認が必要なもの プラグイン。
第五は、IME、マウスカーソル、クリップボード、動画はスタブでよい。

優先順位としては上述のようになるが、確保できる時間を考えて実装するものを考えることも。
例えば、システムカラーなどは数時間で実装できる。

開発は、細かくブランチ切って、出来たら master へちまちま入れて行くのが楽か。
長期間ブランチにして master と離れていくとマージが大変になる。

投稿者 Takenori : 22:29

2016年06月01日

64bit 版をリリースした

吉里吉里Z

32bit 版と 64bit 版の2つが入って容量も増えてきたので、配布サイズを減らすために今回から zip ではなく、7z でのリリースとした。
ファイルサイズは以前の zip より小さくなっている。

更新内容は、更新履歴に書いている。

更新内容一覧の通り、64bit 対応よりも他の修正や追加などが多い。
64bit 対応自体、アセンブリをイントリンシックで書き換えるのが大部分を占めていて、それに伴い MMX から SSE2 への書き換えがあり、それによってグラフィック周りが 30%~数倍高速化されている(機能によって速度差があり、環境や機能によっては遅くなっているものもあるかもしれない)。

投稿者 Takenori : 02:38

2016年06月03日

吉里吉里Zマルチプラットフォーム化クラウドファンディングとAndroid版開発の開始

8月末までの支援を受けて対応項目を絞り込みました。

現在の吉里吉里Zとは互換性のない機能が一部制限/変更されたバージョンの Android 版について開発費が得られたので開発を開始します。
早く完成させるため機能は制限され、互換性が一部なくなるので KAG3 層などは修正が必要となることが予想されます。
制限等は出資者意向です。
制限は、Android 版の制限予定を見てください。

Android 版の開発開始とともにマルチプラットフォーム化についてクラウドファンディングを行いたいと思います。
1万円単位で○万円出してもいいと言う人がいれば、ツイッターメールで連絡を下さい。
その際、希望のプラットフォームを書いてください。
金額的に実現できそうなプラットフォームが確定した場合、再度連絡します。

プラットフォーム
1. Android 版互換性向上(上述の制限を可能な範囲でなくすよう対応)(実装可能金額達成済)
2. iOS 版
3. Mac OSX 版
4. Linux (Ubuntu) 版
5. Linux (Raspbian) 版
6. Chrome OS 版
7. ブラウザ (WebAssembly) 版
8. お任せ(対応プラットフォームは開発者任せ)

各 OS 等に機能がない/異なるなどの関係で完全互換とはならない部分もあります。
例えば Android の場合、マウスカーソルの変更やIME、マルチウィンドウなどサポート出来ない、異なる実装となるものが発生します。

金銭ではなく、ソースコードの寄贈も募集しています。
既に移植している機能がある場合やマルチプラットフォームのライブラリを作っている方は、GitHub のリポジトリなどでソースコードをいただけると助かります。
吉里吉里Z の修正BSDライセンスもしくは、類似のライセンス形態で提供をお願いします。

目標金額
以前達成しなかった吉里吉里Z Android/iOS 対応 クラウドファンディング金額とだいたい同じで、プラットフォーム辺り150万円~200万円です。
同時に実装すれば工数が減ったり、ソースコードでの寄贈があった場合などで変動するので、現在集まっている金額について公開しつつ、それと共に実現できそうか公表していきます。

達成状況

募集期間
2016年8月末をとりあえずのメドとしますが、開発期間中は常時募集します(対応プラットフォームを増やす目的なので)。
WebAssembly対応を2016年12月末まで募集します。

完成時期
まず最初に記載した Android 版の完成を目指します。
その他については2016年中を予定していますが、対応プラットフォームが増えた場合は変更の可能性があります。

投稿者 Takenori : 22:11

2016年06月04日

Android 版の制限予定

Android 版は制限付きで開発すると書きましたが、その制限についての説明です。
これら制限を減らす開発費を得るために吉里吉里Zマルチプラットフォーム化クラウドファンディングを行っています。

グラフィック
グラフィックはハードウェア描画用のインターフェイス(クラス)が追加され、従来のソフトウェア描画(Layerクラス)はオプショナルとなり、機能制限版ではソフトウェア描画は実装されない可能性もあります(工数的な都合です)。
ハードウェア描画用クラスは、従来のLayerクラスと互換性はない予定です。
ソフトウェア描画(Layerクラス)が実装された場合でも Neon 対応は工数的に難しいと思われるので、実行速度的にやや厳しい可能性があります。

Window
Android ではそもそもマルチウィンドウなどはなく、多くの機能が実現できないため、別クラスとして実装されるか、未実装メソッドがある(使用すると例外が発生するなど)状態になります。

KAG3
Android 版では動かず、対応の予定も現在はない。
上述のようにグラフィック周りが大きく変わることが一番大きいです。
(工数的にはソフトウェア描画をサポートさせるほうが KAG3 を動かす工数は少ないと予想される )


その他にも一般的なゲームで必要とされていないような機能は対応されない可能性があります。

投稿者 Takenori : 23:06

2016年06月06日

マルチプラットフォーム化クラウドファンディング 達成状況

マルチプラットフォーム化クラウドファンディングの現在の状況です。

プラットフォーム
1. Android 版互換性向上
2. iOS 版
3. Mac OSX 版
4. Linux (Ubuntu) 版
5. Linux (Raspbian) 版
6. Chrome OS 版
7. ブラウザ (WebAssembly) 版 : 3万円
8. お任せ : 6万円

2, 3, 4, 7 へ8万円

合計 : 17万円


ソースコード寄贈
iOS の OpenGL ES 2.0 初期化コード
オーディオ ( OpenAL/CoreAudio/XAudio ) 共通ラッパー
グラフィック ( OpenGL/DX ) 共通ラッパー
GLFW 対応 ( 自身で対応予定 )
PortAudio 対応 ( 自身で対応予定 )
POCO 対応 ( 自身で対応予定 )

投稿者 Takenori : 13:14

2016年06月16日

吉里吉里Z Android版は将来的に他アプリ連動があると良い?

Android にはデータの共有機能がある。
同じ電子証明書で署名されたアプリからのみにも制限できるので、自分のところのアプリのみデータ共有できるようにも出来る。
インテントによる連携も可能。

連動するとしたら――
1. ゲーム内のデータの共有
2. セーブデータの参照

ゲーム内には音声や画像があるので、ゲームがインストールされていれば、アラームアプリで選択できる音声やキャラクター画像が増える(ゲーム内のデータが使える)、カメラアプリで選択できる画像が増えると言ったことが可能になる。

セーブデータの参照は、ゲーム内の進行情報をアプリに持ってこれる。
攻略するとキャラクターなどが選択できるようになる。
現在攻略しているキャラクターやその状況に応じてアラームのキャラクターやボイスが切り替わる。
ウィジェット系のアプリ、バッテリーメーター等キャラクターが表示されるアプリで、表示されているキャラクターがゲーム内の進行状況で変わる。

他にも色々と連動するアプリは考えられると思う。
毎日目にするアプリでゲームに連動して変化があると、それはゲームを続けるモチベーションにもなる。
RSSリーダーなどを絡め、次回作のリリース時期の案内なども配信すれば認知度を上げられるかもしれない。

インテントによる連携は、何を他アプリに渡すかが難しい。
セリフとスクリーンショットで共有して、ツイッターアプリでツイートできるようにするなどはよくある使い方だと思うが。

アプリ連携が Android の魅力の一つでもあるので、使い道を色々考えて積極的に使っていくと効果的かもしれない。

投稿者 Takenori : 12:51

2016年07月30日

メモリ断片化対策再び

「ビットマップ用メモリを確保できません」と言うエラーが頻発しているようで再び対策。

Twitter での情報によると設定でメモリ確保方法を malloc にすると発生しなくなるとか。

前回のメモリ断片化低減対策で入れた分割ヒープでほとんど発生しなくなると思っていたんだけど、どうもうまくいかない様子(発生頻度が増えると言う報告もあり)。
分割ヒープ + グラフィックキャッシュなし + ghcompact有効化 でどうなのかはわからず。
差分も多く大きいサイズもあるようで、ばらつきが大きいから2分割では効果薄いのか、分割されることで LFH の効果が阻害されているのかもしれず。

malloc にすると発生しないと言う情報を信じて、プロセスヒープから確保するバージョンを実装しブランチに入れた。
デフォルトも GlobalAlloc からプロセスヒープを使うものに変更。
どの方式でもメモリ確保に失敗した時、TJS2 の GC を実行して、ヒープのコンパクションも実行した後メモリ確保をリトライするようにもした。
これで解決するか?

malloc は CRT ヒープから確保されるので、プロセスヒープではないが、CRT 静的リンクの時 exe と dll で別になる。
exe で malloc 確保したものを dll で free して開放したりするとエラーが出る( wrap して exe 側で確保・解放されるようにしているので吉里吉里Zでは malloc 設定でも問題ないはず )。
など、いくつか問題もある。
プロセスヒープは、Win32 API内のメモリ確保などで利用されている様子。
GlobalAlloc は、吉里吉里2の時の実装がそのようになっていたので、Zでもデフォルトはそうしていた。
吉里吉里2は、C++Builder だったし XP 以前 LFH の恩恵もなかったし、メモリ確保周りは色々と変更されてきているから、現在だと好ましくないのかもしれない。
後 Windows10/VC2012 で確認すると GetProcessHeap と _get_heap_handle が同じハンドルを返すので、プロセスヒープと CRT ヒープは今の環境では分割されていないのかもしれない。

設定による挙動の違いなど分かりづらいので、実際にゲームを買って設定いじって見てみることにする。

投稿者 Takenori : 22:52

2016年08月01日

メモリ断片化対策とバグフィック版をリリース

吉里吉里Z 1.3.2 をリリース

64bit対応でグラフィック周り等大きく書き替えられた影響でいくつか不具合が出ていたものを修正した。

メモリ断片化対策は、malloc 設定にすると起きないと言う情報を元にプロセスヒープから確保するものを追加し、それをデフォルトとしたもの。
従来デフォルトだった GlobalAlloc は、大画面化しているゲームでメモリ確保エラーがよく出るようになっているようなので、プロセスヒープを標準とした。
Windows10 で取得したハンドルを見ると、プロセス/CRT 共にプロセスヒープからメモリ確保されるようになっているみたいなので、メモリの分割などはせずに OS がうまくやってくれることを期待する動作となったのではないかと思われる。
今あるどの設定でもダメとなるといよいよもって 64bit 版の出番。
今回のエラー関係のツイートを見るいると 64bit 版を望む声なども見られるので、もしかしたら意外と早く 64bit/32bit の両対応でインストール時に OS 見てどちらかが入るようになるかもしれないと思った。
PC にメモリふんだんに積んでいるのに、1GB とかメモリ確保されている状況でエラー頻発したら、64bit にしてメモリ無駄なく使えよと思うのは仕方ない。

投稿者 Takenori : 15:02

2016年08月03日

ビルドシステムを CMake へ

Android Studio 2.2 から CMake がサポートされるようなので、CMake で一括で管理するように変更しようと思う。
マルチプラットフォームや VC の各バージョン対応なども CMake から吐き出してビルドできると管理しやすい。
VC のプロジェクトファイルと Android 用の makefile など分離していると、片方への追加漏れ等の問題も起きやすい。
現在、VC2012 でビルドされているが、これを CMake から VC2012 用と VC2015 用を吐けるようにして、どちらでもビルドしやすいようにする。
今だと 2012 を切り捨ててしまってもいいかもしれないが。
また、将来的に別プラットフォーム対応する場合も、CMake からビルド出来ると管理しやすい。

vc2012 と言うフォルダ名も、resource/win32 等のバージョン依存しない名前に変更する予定。
Android だと ../res/values などのフォルダになる。
Android.mk などでビルドすると、ある程度名前固定になってしまうけど、CMake でどの程度自由に出来るか調べてフォルダ構成を考える必要がある。

投稿者 Takenori : 14:04

リポジトリの分割とサブモジュール化

リポジトリが大きくなってきているのとマルチプラットフォーム化でさらに膨らむことが予想されるので、リポジトリの分割とサブモジュール化を行いたい。
先行して他に触っている人がいない GitHub pages のドキュメントページを分割してみたがうまく行った。
まずは吉里吉里ZのAPIドキュメントを分割した。
TJS2のドキュメントも分割したい。
これらドキュメントはそれぞれのリポジトリをまとめるメインリポジトリのようなところにdocumentを作り、それ以下にサブモジュールとして配置するとスッキリする。
つまり Web ページとして見られる GitHub pages のリポジトリと開発用リポジトリの2つから参照されることになる。

現在のメインリポジトリは、core 以下のソースコードのみを配置して、軽量化したい。
普段はそこしか触らないのだからフォルダが深かったり、他にいろいろあると重い。
プラグインはそれぞれでリポジトリを分けてしまった方がスッキリする。
サブモジュールとして何を登録するかは考える必要がある。
プラグインは既に本体に機能追加されていたり、使われなくなったようなプラグインはなくしてしまっても良さそう(obsolate plugins などとして分けても良い)。

プラグインは、いくつか分断が発生している。
GitHub のリポジトリと、吉里吉里2 の Subversion リポジトリのどちらか、もしくは両方で変更が入ってしまっていたりして頭痛い状態である。
また、Android 版と共通で使えるように出来るものや Windows 固有のものあるので、plugins/win32 だけでなく、plugins/android、plugins/common 等が必要になる。
吉里吉里2 の方でメンテされているプラグインはどうする予定なのか確認しないといけない。

メインリポジトリが core のみとして、サブモジュールとして束ねるリポジトリは今より入っているものが多くなる。
plugins リポジトリはサブモジュールをネストした方が扱いやすいだろうか? 最初は1段階にして使勝手を見ていくのが良いか?

分割、サブモジュール化は以下の形を予定。
[]がサブモジュール、core が現在のメインリポジトリで、各リポジトリを参照するルートは新規に作る。

  • document
    • [kirikiriz](krkrz-documents)
    • [tjs2]
    • [plugin]
    • [misc](documents)
  • script
    • [Krkr2Compat]
    • [Sample]
    • [test_scripts]
    • [kag3]
    • [kag3_ham]
  • src
    • [core]
      • [bin]
        • win32 - plugin
        • win64 - plugin64
      • ...
      • external
        • [baseclasses]
        • [freetype]
        • [jxrlib]
        • [ligjpeg-turbo]
        • [lpng]
        • [onig]
        • [zlib]
    • plugins
      • win32
        • [...]
    • tools
      • [debugger]
      • [tjs2doc]

core の external 内はサブモジュールのネスト。
GitHub 内にリポジトリがあれば、krkrz グループ内に fork してそれをサブモジュールで参照する形へ。
リポジトリ増えるけど、これですっきりするはず。
bin の位置が変わるので、plugin の出力先の調整が必要。

投稿者 Takenori : 16:08

2016年08月04日

プラグインの分断と整理

吉里吉里Zのリポジトリの方でメンテしていたけど、気付くと吉里吉里2のリポジトリでプラグインを編集している人もいて分断が発生していた。
両方に修正が入っていたらマージが必要になるし、片方だけに修正が入っている場合も最新版がどちらか調べないと行けなくて不具合の温床になる。
この不具合を生む編集方針は DRY 原則に反し、また分岐している意味もないと考えられるので解消したい。
そこで各 Author にどちらのリポジトリで編集していく方針なのか、もしくは不要になったプラグインなのかを確認することにした。
吉里吉里2のリポジトリで編集していく方針であれば、吉里吉里Zのリポジトリにあると紛らわしいし不具合の元なので、削除する予定。

吉里吉里Zのリポジトリにプラグインを入れる時、各 Author にライセンス等問題ないか確認を取って入れたんだけど、何で分岐してしまっているんだろうか……
吉里吉里2のリポジトリでメンテする方針なら、吉里吉里Zのリポジトリに入れないと回答もらえれば今回のような二度手間は発生しなかったんだが。

昔からプラグインが分類されずに大量に並んでいるのを何とかしようと言う話も何度かあった。
Git だと全て一つのリポジトリに入れてしまうと途中の階層から取得できないので、別リポジトリとしてサブモジュールで参照する形にしたいと前回書いたが、その形であれば参照付け替えでカテゴリ分けしやすいだろうか。
フォルダ階層が変わるとプロジェクトファイル等の書き換えが発生するので、結局は一緒か。
別リポジトリになると、どこかで分類を行ってリンクを張ってもいいかもしれない。

投稿者 Takenori : 14:26

2016年08月05日

断片化によるメモリ確保失敗を回避する設定と考察

よく発生すると言うゲームを買って、いくつか設定を試しつつ動かしてみた。
実際に初期設定で動かすと本当に30分~1時間で発生する。


動作を予想しつつ試して、以下の設定にするとほとんど発生しなくなった。

Visual Studio についている EDITBIN で吉里吉里Z本体の exe の LARGEADDRESSAWARE を有効化して、32bit でも 4GB 弱までメモリを使えるようにする。
デフォルトでは 2GB までしか使えない。
ただ、GlobalAlloc などでは特に効果は見られなかったので、設定の意味はあまりないかもしれない。
最新の吉里吉里Z 32bit版では有効にしてビルドされている。


エンジン設定で以下の設定を行う。

画像キャッシュ制限を「キャッシュを行わない」に。
キャッシュに残っているとコンパクションが阻害されてしまうので、ない方が断片化が進行しづらい。
OFF だとスキップなどで速度低下の発生が懸念されるが、最近の PC で SSD なら少し遅く感じるところもあるが許容範囲だと思われる。
なしではなく数百MB(100~200)辺りであれば、それほど影響はないかもしれない。

ビットマップメモリ確保方式は、「分割ヒープを使用」に。

初期分割ヒープサイズは、「1GB」(誤字で1GMBになっているのに気付いた)


エンジン設定後、savedata/exe名.cfu に 「ghcompact="\x79\x65\x73"」 の1行を追記。
この設定はドキュメント未記載(追加忘れていた)。
System.doCompact(clAll) が実行されるシチュエーションで Process/CRT ヒープのコンパクションを呼び出し、断片化の進行を抑止する。


設定は以上。

上記設定で最終的に落ちたのはロック(スクリーンセーバーやディスプレイOFF等)中の描画でのメモリリークっぽいので、ずっとプレイしている状態だと落ちないかもしれない(少し離席して復帰した時落ちていた)。
ロック中の描画でのメモリリークについて解析を進めて早く不具合修正をした方が良さそう。

後、メモリ不足で落ちた時の System.dumpHeap() が欲しいところ。
Bitmapメモリ確保失敗時にログに System.dumpHeap() を書き出して解析できるようにしておく方が良いか。

分割ヒープの場合、その中から画像キャッシュが割かれるので、サイズ自動の時は分割ヒープサイズを考慮して画像キャッシュ容量を決めるように修正した方が良さそう。
外側から見た感じだとこの辺りの予想が限界だが、色々と気付くことがあってよかった。

投稿者 Takenori : 20:16

2016年08月08日

ビットマップメモリ確保失敗追加対策等

断片化によるメモリ確保失敗を回避する設定と考察に書いたような対策を加えたスナップショットを公開した。

動作を見て加えた対策だけど、今後気付くことがあったらまた追加対策する可能性はある。
これでも厳しいようなら 64bit版使えばいいと思う。
64bit版対応は、プラグイン対応とテスト工数の問題だろうけど、このメモリの問題に延々と悩まされるくらいならさっさと 64bit版対応した方がみんな幸せ。

・ロック画面での描画でメモリ消費量が増大する問題を修正。
・ghcompact が設定に漏れていたので追加。
・Bitmap メモリ確保失敗時、ヒープの状態をダンプして解析を進めやすいように追加。
・Bitmap 用分割ヒープ割当量計算方法を変更。
・分割ヒープを仮想メモリの空きと物理メモリで少ない方を基準に計算するように変更。
・グラフィックキャッシュを物理メモリより仮想メモリの方が小さい(32bitでメモリ搭載量が多い)場合、仮想メモリの方でキャッシュ計算するように変更。


追加したエンジン設定の ghcompact はデフォルト OFF。
ON にすると System.doCompact が実行されるタイミングで、idle 以上ならヒープのコンパクションも実行されるようになる。
以前は、clAll の時に限定していたが、デフォルト OFF でそこまで負荷も高くないようなので、idle 以上とした。
動作下限とする CPU のマシンで動かして負荷が気にならないのなら、デフォルト ON 設定にしてしまってもいいと思う。

今後ビットマップメモリ不足が発生した時、ヒープの状態から解析を進めやすいようにログにヒープ状態ダンプを行うようにした。
ログからフラグメンテーションがどれくらい進行しているかわかる。

分割ヒープ容量が自動の場合、空きメモリの内の割り当て量が以前よりも多くなるように調整した。

グラフィックキャッシュ容量が自動の場合、以前は物理メモリ量を基準に計算していたが、32bit の時は物理メモリの方が多いケースもあるため、仮想メモリ容量(32bitの時LAA有効で4GB、無効で2GB)と比較して小さい方基準で計算するように変更した。


前回のリリースでプロセスヒープをデフォルトとしたが、個人的には分割ヒープの方が有効ではないかと思っている。
今回のバイナリで利用が激しい環境でテストしてみないことにはどちらの方が発生しづらいかはわからないが。
ビットマップメモリ確保失敗が頻発するようなら、比較確認して結果を教えてもらえると助かります。
スクリプト側では、シーン切り替えの暗転時などに System.doCompact を呼ぶと少し効果があると思われる。
グラフィックキャッシュは使わないか、出来るだけ少ない容量にした方がメモリのフラグメンテーション抑止に効果がある。

投稿者 Takenori : 20:53

2016年08月29日

吉里吉里Zで扱われる各種文字コード

TJS2 内部文字コード

UTF-16LE

テキスト(スクリプト)読み込みの文字コード

UTF-16LE、UTF-8(BOM)、UTF-8 or ShiftJIS(CP932) に対応している。
BOM が付いている UTF-16LE と UTF-8 の場合、BOM によって文字コードを判別し、認識した文字コードで読み込みが行われる。
それ以外の場合は、デフォルトでは UTF-8 となる。
コマンドラインオプションの -readencoding で文字コードを指定した場合、その文字コードで読み込まれる。
Scripts.textEncoding で文字コードを指定した場合、その文字コードで読み込まれる。

テキスト書き出しの文字コード

UTF-16LE

バイトコード・バイナリ Dic/Arrya の文字コード

UTF-16LE

コンソールログ出力の文字コード

UTF-16LE
コマンドプロンプトでない場合は、ShiftJIS(CP932) になっている。
UTF-8 出力指定オプション追加の要望がある。

コマンドライン読み込みの文字コード

UTF-16LE

ソースコードの文字コード

現在のビルドされているものは ShiftJIS(CP932) だが、次のバージョンから UTF-8 になる。
dev_multi_platform ブランチでは既に UTF-8 に切り替え済み。
ShiftJIS だったのはずっと日本語 Windows で開発されていたからだが、マルチプラットフォーム化に伴いダメ文字などによる問題を回避することと、Visual Studio 2015 Update 2 で BOM なし UTF-8 がサポートされ準備が整ったことで UTF-8 へ移行。

プラグインスタブの文字コード

現在は ShiftJIS(CP932) 。
今後どうするか要検討。

実行ファイル内文字コード

ShiftJIS(CP932) or UTF-16LE
ほとんどワイド文字列として定義されているので UTF-16LE 。
マルチプラットフォーム化に伴い ShiftJIS(CP932) は UTF-8 にしてしまった方が良いと考えられるので変更予定。
UTF-16LE に関してはエントリーにて詳細を書く予定。

投稿者 Takenori : 21:51

wchar_t サイズ問題

wchar_t は、Android では 4バイトで Windows では 2バイト。
コンパイラのオプションで変更は出来るが、意図しない問題が発生する可能性があるため、それは好ましくない。
サイズ依存しないように対応することも出来るが、注意しないと問題が発生する可能性があるのと、テキスト ( スクリプト ) 読み書き等ファイルアクセスする時毎回変換が入る ( セーブデータが環境ごとに異ならないようにするためと UTF-16LE のスクリプト対応 ) 。

どうするか?

・tjs_char の定義を wchar_t ではなく、char16_t に変更する。
・定数文字列は L"" ではなく、u"" とする。
・std::wstring は std::u16string を使用 ( tjs::string などと定義 ) する。
・文字列処理の標準ライブラリは、自前で準備する ( Bionic から持ってきて書き換える、TJS_xxx マクロを関数化 ) 。

これで問題なくなるはずなので、この方法で対処を試みる。


以下、char16_t を知らなかったので、色々検討していたことだけど、無駄だった。

吉里吉里では tjs_char を使用しているので、Android などでは typedef tjs_char unsigned short として、文字列処理関数類は Bionic から持ってくるのが良いのではないかと最初考えた。
文字列処理関数も TJS_xxx と言った名前が使われているため、define で別名を与えるのではなく、別実装としてしまえば問題ない。
また、文字列処理関数も SIMD 化可能なので、SIMD 化する時も都合が良い。

ただし、この対応でも実行ファイル内文字コードの問題が解決しないことに気付いた。
TJS_W で埋め込んでいるが、これは L"" で wchar_t の文字列であり、サイズ問題が発生する。
文字列の埋め込みは極力止めて、リソースに文字列を逃がし、多言語対応するようにしているが完全ではない。

1. 文字列の埋め込みは極力行わずリソースに格納する。
2. L"" の使用は中止し、"" に変更を行い実行ファイル内文字コードは UTF-8 とし、必要に応じて UTF-8 から UTF-16 に変換を行う。

1番はいいとして、2番の判断をどうするか。
注意を必要とするが問題ないと思えたものの、__TIME__ などの定義済みマクロを使用する箇所で変更が必要。

-fwide-exec-charset で utf-16 にするか? これはコンパイルオプションと同じく注意が必要になる。

TJS_W を非 Windows 環境では関数とし、非ワイド文字 ( UTF-8 ) を受け取り、UTF-16 を返すようにする。
受け取るのは定数なのはわかっているので、変換テーブルを持って対応する。
うまく行きそうだが少しトリッキー。

std::wstring 問題も残る。
namespace tjs {
typedef basic_string string;
};
とする。

Java との受け渡しは jchar ( unsigned short UTF-16 ) か、UTF-8 から変換して渡すメソッドを使う。
Java は UTF-16 なので、jchar で直接渡す方が効率が良さそうではあるが、気にすることのほどではないようにも思う。

投稿者 Takenori : 21:59

2016年09月02日

ソースコードのUTF-8化とVisual Studio 2015への移行

dev_multi_platform ブランチでは先に UTF-8 化と Visual Studio 2015 への移行を行っていたが、master もそれに合わせていないと不便と言うことで、master も追従した。
vc2012 フォルダは vcproj に変更になっている。
また、exe の出力先は bin 以下ではなく、clone した krkrz と同じフォルダ、つまり1個上に出力されるようにした。
plugins フォルダを plugin に変更して、各プラグインも1個上に dll が出力されるようにすれば、そのまま読める形。
スクリプトも data フォルダを krkrz と並列に置けば動く。
階層が深い構造を出来るだけ浅く、リポジトリが分離されても開発しやすいようになるべく並列に置いて開発できる形へ変えていく。
ソースコードが UTF-8 になり、/source-charset:utf-8 が指定され、外部ライブラリでよく出ていた文字コードの問題はこの指定で消えてすっきり。
非日本語環境や他環境用コンパイルでも問題が減ることが期待できる。

各種ライブラリは submodule に分離されているので、最初に clone した時に submodule の初期化を忘れずに。
それをしないとソリューション読み込んだ時プロジェクトファイルがないと言って怒られる。

投稿者 Takenori : 20:36

Dictionary.loadStructでテキスト形式でも読めるように対応

吉里吉里2/Zに脆弱性があると言う話 でバイナリ形式は対応していたが、テキストはまだだった。
何度もニュースを目にして煩わしいので、テキストも対応することに。
(const) 付きの Dictionary/Array はそれぞれを生成するバイトコードが出力されるのではなく、読み込み時に各オブジェクトが生成されてデータ領域に置かれ、バイトコード自体はデータ領域からレジスタにコピーして、そのレジスタを return すると言う3つの命令が生成される形になるため、loadStruct から呼び出された時は、スクリプト(top level)の実行は行わず、データ領域から直接 result へコピーしてしまうようにした。
これでテキストのセーブデータを var savedata = Dictionary.loadStruct("data.dat"); のようにして読み込めばスクリプトが実行されることなく読み込める。
まあ、前回のバイナリと同じ。

ただ、バイナリのように全て対応はしておらず、上記 Dictionary.loadStruct とした呼び出しのみ対応。
インスタンスを指定してそこに読み込ませたり、Array で読み込ませたり、Dictionary で Array のデータ読んで例外などはまだ対応していない。
完全対応ではないが、実際に使う分には何ら問題ないはず。
これでテキストでもバイナリでもセーブデータをデータとして読み込めるようになった。

投稿者 Takenori : 20:54

2016年09月07日

8末までマルチプラットフォームクラウドファンディングを受けて

現在集まっている金額から考えて、Android 版互換性向上とブラウザ (WebAssembly) 版 を優先することにしようと思います。
ただ、WebAssembly に関しては現在の金額では厳しいため、引き続き支援を募集したいと思います。

Android 版互換性向上は、ソフトウェア描画を実装し KAG3 などの動作で最もネックとなる部分を解消します。
ソフトウェア描画の動作速度を見て、SIMD(neon) には非対応もしくは基本的なアルファブレンディングのみ対応を検討します。
マルチウィンドウは非サポートなので、Yes/No ダイアログ等モーダル Window で実現しているものは、Layer 等で描画するよう修正の必要がある形に。

残りは WebAssembly へ。
SIMD(neon) 対応せずにソフトウェア描画のみの対応であれば、大して工数かからないため、そこそこ WebAssembly に工数使えると思うが、今の金額だと完全対応はかなり厳しい。
WebAssembly に対応すれば、他のプラットフォームも対応できることになる。
Windows / Android / iOS / Mac OSX / Linux / Chrome OS で動く、もしくはもうすぐ動く。
PC(Windows/Linux/Mac OSX) であれば、htmlファイルと共に配布して起動してもらうこと、node-webkit 等に組み込んで配布することも可能なはず(組み込んで配布はまだ対応していないかもしれない)。
Android/iOS は、WebView で実行するアプリ化やサーバー経由での動作となると思われる ( WebAssembly 対応が次かその次くらいのOSバージョンとなると思われるので、Android はネイティブ対応したものを使う方がいい )。

WebAssembly 第1目標は、TJS2 WebAssembly コンパイラ (wasm 上で動作)を作ること。
ただ、現在集まってる金額ではきちんとコンパイルできるところまで作れるかどうか厳しいところ。
調査、環境整備、ドキュメント整備で終わってしまうかもしれない。
作るものは TJS2 スクリプトを wasm のテキストもしくはバイナリにコンパイルする。
wasm 上に TJS2 VM を実装するのではなく、サポートクラスを使い wasm でネイティブで動作するようにする。
コンパイラはネイティブプログラムではなく wasm として動作するものにする。
wasm として動作することで、eval などの呼び出し時に動的に wasm バイトコードへのコンパイルを行って実行することが可能になる(これがなければ TJS2 VM の実装が必要になってしまう)。
JavaScript が提供するブラウザAPI の呼び出しを TJS2 上から可能にする。
ここまでが最初の目標。

吉里吉里Z が提供する組み込み API は当初実装しない(現在集まっている金額では工数的に厳しい)。
吉里吉里Z 互換とするための API は TJS2 で記述することで、上位システムは他プラットフォームと共通とすることが可能(この方向を指向)。
VM を実装せず wasm バイナリ化するため JIT でネイティブ動作されると思わるため、吉里吉里Zなどよりも高速に動作する可能性が高いが、動的言語のため関数呼び出し等の検索のオーバーヘッドが大きく、ネイティブと比べて速度的にかなり不利になる。
これを解消するため、C# の sealed class のような動的に変更が出来ないクラス機能を追加し、型指定との組み合わせによってネイティブと遜色ない動作速度を実現し、下位層を TJS2 で実装しても問題ない速度で動くようにする(上位のシステム部分は互換性のためこの機能は使わないことを想定するが、吉里吉里Z では sealed などのキーワードが単純に無視される形で組み込まれることも検討)。


以下、別作業や将来的なこと
API リファレンスを疑似コードからマニュアル生成するツールに切り替えるべく、現在の xml 形式から疑似コードとヘッダーコメントの形式へ書き換える。
これをやっておけばメンテナンスしやすくなるし、疑似コードは一種のスタブでもあるので、吉里吉里Z 互換層を TJS2 で書く時の下地として使え、内部を埋めることでブラウザで吉里吉里Z 互換が可能となる。

ブラウザでは、描画は WebGL を使用することとなると思うが、これは実質 OpenGL ES2.0 なので、Android 版で導入されるハードウェア描画とほぼ等価な機能が実装可能であると考えられ、将来ハードウェア描画を主体としたシステム (KAG 等)に切り替えられれば、ブラウザ上でも遜色ない見た目を実現できると思われる。

投稿者 Takenori : 22:31

2016年11月21日

Windows版/Android版文字の取り扱い

吉里吉里Z 内部では UTF-16 で処理され、wchar_t を使用している。
wchar_t は、Windows では 16bit だが、Android では 32bit になる。
この差をどのように取り扱うか検討する必要がある。

1. wchar_t で統一し、ファイルのやり取りなどの部分のみ環境固有にする。
2. char16_t で統一し、Win32 API などに受け渡す時はキャストする。
3. Windows は wchar_t、他は char16_t にする。

1.の場合
wchar_t で統一すると文字サイズが異なるためファイルの読み書きなどで互換性がなくなる。
動作自体はほぼ問題なく動く。
ただ、ファイル読み書きで互換性がないのは困るので、環境に応じて処理を分ける必要がある。
Windows 基準で作られているので、Android は別実装になる。
また、Java と文字列をやり取りする場合、jchar は 16bit のため毎回変換が必要になる。

2.の場合
C++11 以降 wchar_t は非推奨となっていて、Unicode 用の char16_t や char32_t が使えるようになっている。
char16_t で統一してしまえばすっきりする。
ただ、文字列処理関数として char16_t のものは少ないので、別途準備する必要がある。
Win32 API では、文字列を wchar_t* で受け渡すものがあり、これは char16_t だとキャストしないといけない。
キャストの場合ミスがあると実行時に問題となって表れるので、避けられるのなら避けたい。

3.の場合
キャストの問題を避けるために Windows は wchar_t 、Android は char16_t にする方法。
char16_t なので文字列処理関数を準備する必要があるのは 2の場合と同じ。
実装上のミスはキャストと比較してコンパイル時にわかりやすいのでやや安心。
環境によって定義が異なるのがややすっきりしない。

方法とメリットデメリットはこんなところ。
今回は、3番を選択した。
実装は――
tjs_char を環境によって wchar_t か char16_t として定義して、内部では tjs_char で統一。
tjs_string を環境によって std::wstring か std::u16string として定義して、内部では tjs_string で統一。
文字列定数は、TJS_W を環境によってマクロで L""か u"" として定義して、内部では TJS_W で統一(単一文字も同じ)。
とした。
また、文字列処理関数は主に bionic からコピーし、tjs_char として書き換えた。
文字列処理関数を自前で持つことで SIMD 化を行いやすくもなった(ランタイムで既に SIMD 化されていたりもするので速度低下している部分もあると考えられるが)。

投稿者 Takenori : 02:24

2016年11月25日

デフォルトフォントの選択

吉里吉里2ではMS Pゴシックがデフォルトで、吉里吉里Zも初期は同じようになっていた。
多言語対応でそれでは困るということから、日本語環境ではそのまま、他の環境では DEFAULT_GUI_FONT (メニューやダイアログボックスのような UI の既定のフォント)がデフォルトとなるようにした。

Android では、/system/fonts/ 内に各種フォントファイルがあり、fonts.xml/system_fonts.xml/fallback_fonts.xml と言ったファイルに使用されてるフォントが記述されている。
ただ、xml ファイルの方は Android のバージョンによって異なり、少なくとも 4.X と 5.0 以降では記述方法が変わっている。
Android アプリでは Typeface クラスを用いてフォント指定を行うので、このクラスからファミリー名等が取得できればそこから fonts.xml 等の違いを気にせずフォントを取得できるが、残念ながらそれはできない。
Typeface クラスはほとんど情報を公開しない。
では、やはり fonts.xml 等を自前で解析し、各バージョンに対応するべきか?
これは将来的にまた記述が変わった時動作しなくなってしまう問題をはらむので、避けた方が良いと考えられる。

一番安全なのは assets に使用するフォントを入れて、それをデフォルトとすることなので、この方法を推奨しつつ、指定されない場合はロケールによってほぼ決め打ちにする。

まず、Font クラスにスタティックメンバで以下を追加する。
Font.addFont(filename) : facename[] (freetype でのみ有効。指定ファイルが持つフォントを内部の管理領域へ追加する)
Font.defaultFaceName (変更してもこれ以前に生成されたレイヤー等には影響しないので、変更する場合は Window 生成などより前に設定する必要あり)
この2つのメソッドとプロパティによって、スクリプトで assets のフォントを読み込み、デフォルトフェイス名を変更することで、assets に入れたフォントがデフォルトで使われるようにできる。
assets に入れないがロケールの影響を無視して日本語表示したい場合は、以下に記述しているファイルを読み込ませ、それをデフォルトとすればよい。
フォント決め打ち設定はスクリプト実行より前に行うので、スクリプトで変更すれば問題ない。

Windows 版の IME で使用されるフォントがレイヤーで指定されたフェイス名で生成できない時は、DEFAULT_GUI_FONT で設定されているフォントが使用されるように変更する。
昔は動作不定となっていたが、デフォルトフェイス名変更によって IME で設定失敗する率が高まるので、動作を妨げない対応を追加した。

決め打ちのフォントは Locale.getDefault().getLanguage() によって設定する。
ja : NotoSansJP-Regular.otf > MTLc3m.ttf > MTLmr3m.ttf
zh-Hans : NotoSansSC-Regular.otf : 簡体字(中国)
zh-Hant : NotoSansTC-Regular.otf : 繁体字(台湾)
その他 : DroidSansMono.ttf

設定は上記4種のみ。
ja の時は Noto 優先で、なければモトヤフォントとなる。
見付からない場合は、/system/fonts/ を検索して最初に見つかった適していそうなフォントにしてしまう。
それでもなければ DroidSansMono.ttf を設定する。
DroidSansMono.ttf もない場合は、/system/fonts/ にある最初に見つかったフォントにする。
Note かモトヤフォントはあると思われるので、そのどちらかに決まるはず。

ロケールとゲームで表示する言語は別である可能性もある。
ゲームではデフォルトのフォントに頼らず、自分でフォントを設定することが推奨される。

システムのロケールとは別にエンジンロケールの設定の追加も検討中。
ただ、エラーメッセージの問題がある。
エラーメッセージが多言語化されると、システムのロケールでメッセージが確定するので、その言語に従ったフォントが必要となる。エラーメッセージが内部の LogCat とファイルにのみ書き出されるのであれば、気にすることではないが。
この辺りの問題については、初期バージョンは気にせず、のちのバージョンで対応を検討している。

投稿者 Takenori : 19:21

2016年12月01日

エンジンのバージョン番号

吉里吉里Z のバージョン番号はログや About ダイアログなどで表示される。
Windows 版ではリソースにバージョン番号が埋め込まれている。
Android アプリは AndroidManifest.xml ファイルにバージョン番号を記述する。
最初 Android 版はこのマニフェストからバージョン番号を引っ張ってくれば良いと考えて実装したが、よく考えたらこれは好ましくない。
マニフェストに記述するのはアプリのバージョン番号であって、これはアプリの更新等に依存する。
つまり、エンジンのバージョンとして取得するわけにはいかない。
そこでエンジンのバージョン番号はソースコードに直接埋め込んだ。
ただソースに埋め込んでしまうのは少し好ましくないので、"res/values/integers.xml" にでも記述してそこから取得するように変更する予定。

投稿者 Takenori : 03:42

2016年12月02日

TickCount は timeGetTime/clock_gettime で

元々 Windows では timeGetTime で取得していたが、Android 版と共通化できないかと C++11 chrono で実装してみたが、乱数で偏りが大きくなるようなのでやめた。
乱数シードに TVPGetRoughTickCount32 等で得られる値を TVPPushEnvironNoise で追加しているが、chrono を用いて起動時からの経過秒数(ミリ秒)を返すように実装すると、TJS2 スクリプトで最初に乱数生成器を作っていると偏りが大きいように見えた。
乱数のシードに入れるものだけエポック秒にしてもいいが、共通化のために二種類準備するよりも単純に環境によって場合分けする実装にすることにした。
Windows は元の timeGetTime、Android は clock_gettime( CLOCK_MONOTONIC, &now ) とした。
Android のソースコードで SystemClock.uptimeMillis() の実装を見てみると、CLOCK_MONOTONIC が使われていたのでそれに準じた。同様の機能だと CLOCK_BOOTTIME かとも思えたが。
これで両方元の実装(システム起動時からの時間取得)と同じ機能となった。
吉里吉里起動時からの時間でもほとんどの場合困らないのだが。

投稿者 Takenori : 12:26

2016年12月03日

起動優先順位

Windows 版でいう data.xp3 から起動するなどの設定。

Android 版
利便性を考えるとリリース用と開発用は別にした方が良い。

リリース用は――
1. assets 内の data.xp3
2. assets 内の startup.tjs
(3. data.so ファイル)

開発用は――
1. 明示的 Intent で他アプリから指定されたファイル
2. 暗黙 Intent で他アプリから指定された xp3 or tjs ファイル
3. ストレージ アクセス フレームワーク(SAF)でのファイル選択( Android 4.4 以降 )

リリース用 1, 2番は特に説明することもないとおもうけど、assets 内に対象のファイルがあったらそこから起動する。
3番は実装するか未確定だけど、クラッキング対策として共有ライブラリ。初期呼び出しメソッドを固定し、スタートアップスクリプトの返却と StorageMedia の登録等を行う。

開発用 1番は他アプリから起動要求された xp3 or tjs ファイル。
2番はファイラー等で xp3 や tjs ファイルが選択された時にアプリ起動するというもの。
3番は Android 4.4 から使えるファイル選択 UI 経由での起動。GoogleDrive などでも行けるはず。


以上のように考えている。

投稿者 Takenori : 19:52

2016年12月09日

ファイル選択とSD保存

Android でのアプリからの SD 保存は、4.3 まではできたけど、4.4 で禁止(毎回ユーザー認証)、5.0 以降ユーザーのフォルダ許可で可能と言うのがざっくりとした流れ。
また、SD がマウントされているディレクトリを得る統一された方法はなく、機種依存で何パターンかある。
Google の Nexus シリーズは SD 対応しておらず、あまり認めたくないようだけど、需要あるので渋々と言う印象がある。
吉里吉里Z の Android 版は、4.2 以降を想定しているが、4.2/4.3 のために 機種依存の SD マウント場所を得るのを何パターンか実装するのは労力に見合っていないように思う。
そこで外部ストレージのアプリデータ保存場所として得られるディレクトリにデータ保存するのを基本としつつ、5.0 以降用にユーザーがフォルダ選択して、そこにファイル生成や保存ができるようにするのが妥当だろう。
フォルダ選択は、ストレージ アクセス フレームワーク(SAF) と言う仕組みを利用する。
SAF はファイルアクセスを抽象化し、DocumentsProvider と言うプラグインのようなもの(アプリとして提供される)を追加することで、様々な場所へのファイルアクセスを可能にする。
デフォルトでは、端末のストレージと GoogleDrive が利用できる。
つまり、5.0 以降であれば GoogleDrive にセーブデータを保存して PC と共有するといったこともやりやすい。
( SAF は 4.4 から対応されているが、4.4はファイル単位での選択なので毎回選択の必要があり使い勝手が悪い )

仕様を整理すると――
・保存場所のデフォルトは、外部ストレージアプリデータ保存場所。
・4.4 以降でファイル選択機能使用可能。
・5.0 以降でフォルダ選択機能使用可能。
となる。

投稿者 Takenori : 03:05

2016年12月19日

Android 版はファイル名の大文字小文字を区別するように

吉里吉里2/Z はファイル名の大文字小文字を区別しない(ケースインセンシティブ)。
Android 版も同じような動作を考えていたが、実装上解決できないので区別することにする(ケースセンシティブ)。
問題は、同名の大文字小文字だけが違うフォルダ or ファイルが存在した場合、識別できないから。
Windows/MacOSXはファイル名の大文字小文字は区別しないが、Android/Linuxは区別する。
このOSの違いによって上述の仕様差異が生じる。

ただし、XP3アーカイブに入れたファイルはどちらの環境でも大文字小文字を区別しない。
これは OS の影響を受けないため。

上記、Windowsは区別しないと書いたが、厳密にいえばプラグインによっては区別するものが存在する可能性はある。
吉里吉里は、プラグインによって任意のストレージを追加できるが、大文字小文字を区別するかはそのストレージを追加する処理に依存する。

仕様を整理する
1. XP3アーカイブ内のファイルは環境にかかわらず大文字小文字を区別しない。
2. Windows 版はローカルファイル/フォルダの大文字小文字を区別しない。
3. Android 版はローカル/Asset/SAFのファイル/フォルダの大文字小文字を区別する。


以上のようになる。
リリース時にXP3にすべてのファイルを入れる形であれば違いは表面化しない。
確か KAG3 はファイル名の大文字小文字は気にしない実装だったので、区別する環境で動かすとエラーが出る。
ファイル/フォルダ名はすべて小文字にするなどの対応を取っていれば問題はあまり表面化しない(元々あるディレクトリにアクセスする場合は意識する必要がある)。


もし Android でこの制限を回避する妙案があったら教えてください。

投稿者 Takenori : 23:20

2016年12月20日

ストレージアクセスフレームワーク(SAF) のパス

・ディレクトリ選択 ( ACTION_OPEN_DOCUMENT_TREE ) の場合、URI で返ってくるのは、外部ストレージの時 content://com.android.externalstorage.documents/tree/primary: + フォルダパス。
・ファイル選択 ( ACTION_OPEN_DOCUMENT ) の場合は、content://com.android.externalstorage.documents/document/primary: + ファイルパス。

primary の後のコロンとスラッシュは文字列で取得するとエスケープされている。

ディレクトリ選択で取得した URI で DocumentFile.fromTreeUri を使って開き、DocumentFile.listFiles でファイルリストを取得した場合の URI はどうなるか?
「content://com.android.externalstorage.documents/tree/primary: + フォルダパス + document/primary: + ファイルパス」になる。
長い上に単純にファイル名を結合したものではなく、パス部分すべてが結合された状態になる。
DocumentFile.getUri で取得すると上記のようになる。
DocumentFile.getName でディスプレイ名を取得して、/ を間に入れて無理やり文字列結合した場合 DocumentFile.isDocumentUri で false となる。
ディスプレイ名を使って URI を取得したいときは、ツリーの DocumentFile に対して DocumentFile.findFile で検索する必要があるようだ。

外部ストレージの場合、URI の最後 / (%2F) 以降がファイル名 = ディスプレイ名となっているが、GoogleDrive の場合は異った。
URI が REST のような末尾 /acc=1;doc=1 になっている。
DocumentFile.getName すればファイル名が得られる。
ただ、得られる名前は DocumentsProvider の実装依存でもあるので、必ずファイル名とも限らない。


吉里吉里2/Z のファイルパスは、ディレクトリのパス + / + ファイル名を期待した作りになっている。
TVPGetPlacedPath 内でファイル名をテーブルから検索して、見付かった場合に パス + ファイル名 で強制的に結合される。
これらを踏まえて Android版で SAF を使用したファイルアクセスをどうするか。

1. iTVPStorageMedia を拡張して(一部プラグインに影響する破壊的変更)、パスとファイル名の結合をメディアストレージに依存する実装に変える。
2. GetLocallyAccessibleName で、最後の / 以降はディスプレイ名が使われているという前提で、/ でパスとファイル名を分離し、期待するパスを生成する。

簡単に思いつくのはこの2つ。
1 は一部互換性を破壊しつつも、SAF のようなシステムを考慮したスマートな仕様に思える。ただし、このようなシステムがどの程度あるのか疑問で、この特殊な例のためだけに変更するのが良いかどうか。
2 はやや泥臭いが互換性は破壊せず、GetLocallyAccessibleName と言うメソッドも意図した動作をするように実装される。

2番で行く。

投稿者 Takenori : 22:56

2016年12月21日

システムのパス

System クラスのプロパティで各種パスが取得できるが、これらのパスは OS 固有。
今まで Windows しかなかったので、Windows 固有のパスを基準に作られている。
Android 版では、完全に別にしてしまうか、ある程度互換性を持たせるかの選択肢があるが、可能な範囲で用途的に同等と思われるパスを割り当て、Android 固有のパスを増やす形にする。
Android 版では以下のようなパスを割り当てることを考えているが、外部ストレージに関してはマウントのチェックなどもあるので再考するかもしれない。
再考時はアプリのアンインストールで削除される、アプリリストのデータ削除やキャッシュ削除で削除される等の挙動も考慮する。

System.appDataPath = Context.getFilesDir() ex) /data/data/{パッケージ名}/files
System.dataPath = Context.getExternalFilesDirs() ex) /storage/emulated/0/Android/data/{パッケージ名}/files
System.exeName = Context.getPackageCodePath() ex) /data/app/apkname.apk
System.exePath = Context.getPackageCodePath() ex) /data/app/
System.personalPath = Context.getExternalFilesDirs()ex) /storage/emulated/0/Android/data/{パッケージ名}/files
System.savedGamesPath = 対応するものなし

System.exePath は、apk が置かれるパスが相当すると思うが、Windows と違って Android では取得する意味がないと思われる。
System.exeName も、apk のファイル名を含んだフルパスであるが、これもあまり意味がない。
一応、apk は zip なので、吉里吉里Z 本体で展開して中のファイルをあれこれと出来なくはないが、意味は薄い。

Android 固有のパスは色々あるので、また後日リストアップする。

投稿者 Takenori : 23:19

2017年01月23日

Android版のサウンドの制限

Android の OpenSL ES 仕様上発生する Windows 版の現吉里吉里Z 制限とは異なる制限。
ソフトウェアで事前に変換することで(表面上の)制限をなくすことは可能ではあるが、初期は行わない予定。

以下、具体的な制限。

・ 8 ビット符号なしまたは 16 ビット符号付き
(浮動小数点データでの再生は、Android 5.0 以降でのサポート。Android 版は初期は実装しない予定)

・モノラルまたはステレオ
( Windows 版はさらに多チャンネルサポートしているが Android 版は非サポート)

・サンプルレート
8000,11025,12000,16000,22050,24000,32000,44100,48000Hz
( 48000Hz を推奨。推奨値は端末依存だが 48kHz が多い模様。レイテンシ低減に効くとドキュメントに記載)

・同時再生数 32
(ドキュメントでは object と言う表現なので、もしかしたらもう少し少ないかもしれない。また OpenMAX AL と共有とのことなので動画もこの数に含む。自前でミキシングすればこの上限は関係ないが、そこまで厳しい制限でもないため現状上限はこのままの予定)


Audio output latency に低遅延に関する情報がある。
デバイスの最適サンプリングレートとバッファサイズを使用して、無音出力して準備するというものであるが、そこまでは行わない予定。
リップシンクや UI でタップ音などで遅延を感じる可能性はある。
あまりにひどいということであれば対策を考えるが、現在は 48kHz を推奨し、48kHz の時はバッファサイズを推奨サイズの倍数にするというところまでの対策にとどめる。

投稿者 Takenori : 16:54

2017年02月18日

XAudio2

DirectX のバージョンによって 2.0 ~ 2.7 がある。最新版である 2.7 を対象とすれば問題ないと思われる。
Windows8 は 2.8、Windows10 は 2.9 となっている。
環境にある DLL の xaudio2_7.dll、xaudio2_8.dll、xaudio2_9.dll の内、新しいバージョンの DLL をロードすればよさそうであるが、それだけではうまく動かなさそうである。

ヘッダーファイルを見るとバージョンによって、構造体にメンバが増えていたり、インターフェイスにメソッドが増えていたり、メソッドにパラメータが増えていたりするので、別物として扱う必要がある。
2.8 と 2.9 はヘッダー共通なので、2.7 とそれより後の 2 パターンで使用するメソッドについてラッパーを書けば両バージョンに対応できなくはなさそうである。
dll から XAudio2Create 関数を得て、それ以降で得られるインターフェイスの IXAudio2 などを別物として扱えば、理屈上は両方に対応できるはずである。
もしくは、Windows7 以下を切り捨てるのなら、2.8 と 2.9 のヘッダー(インターフェイス/構造体)でそのまま使える。

Windows7 を切らないという選択を選ぶのであれば、namespace とファイル分離、Factory によって何とかするのが記述量一番少ないと考えられる。
以下のような実装。

namespace xaudio2_7 {
#include "xaudio2_7.h"
#include "xaudio2driver.h"
};
IXAudio2Driver* CreateXAudio2Driver7(HMODULE hDll){...}


namespace xaudio2_9 {
#undef _WIN32_WINNT
#define _WIN32_WINNT _WIN32_WINNT_WIN8
#include "xaudio2_9.h"
#include "xaudio2driver.h"
};
IXAudio2Driver* CreateXAudio2Driver9(HMODULE hDll){...}


extern IXAudio2Driver* CreateXAudio2Driver7(HMODULE);
extern IXAudio2Driver* CreateXAudio2Driver9(HMODULE);

IXAudio2Driver* pDriver = nullptr;
HMODULE hDll = LoadLibrary(L"xaudio2_9.dll");
if( !hDll ) {
  hDll = LoadLibrary(L"xaudio2_8.dll");
}
if( hDll ) {
  pDriver = CreateXAudio2Driver9( hDll );
} else {
  hDll = LoadLibrary(L"xaudio2_7.dll");
  if( hDll ) pDriver = CreateXAudio2Driver7( hDll );
}
return pDriver;

// ここでは放置しているが hDll は使い終わったら FreeLibrary する。
// IXAudio2Driver は自前のインターフェイス

xaudio2_7 と xaudio2_9 でファイルを分離するのは define で定数等定義されているから。
xaudio2driver.h 内に通常の実装を入れて include することで2回書くのを回避する。
xaudio2_7.h は、DirectX SDK のヘッダーをリネームして置いて、xaudio2_9.h は Windows SDK の方のヘッダー。

と書いたものの、ここまでして実装した方がいいかは疑問。
XAudio2 に比べれば複雑になるものの、DirectSound よりは記述量少なそうな WASAPI を選択する方が良さそうに思える。

投稿者 Takenori : 04:30

OpenSL ES と XAudio2

ループチューナ で指定されたループやラベル等吉里吉里 2/Z のサウンド部分は複雑なので、PC でデバッグできると効率が良い。
ただ、OpenSL ES と DirectSound は API 体系がだいぶ違うので共通化は大変。
XAudio2 は OpenSL ES とほとんど同じで、データがなくなるとコールバックで呼ばれ、バッファをキューに入れていく形になっている。
インターフェイスで実装を分離すれば、基本部分は共通化できるのでそうした。

せっかく実装したのだから、PC 版では XAudio2 か DirectSound かを選択できる形にしようと思い、XAudio2 についていろいろと調べてみたが手間がかかりそうなので、共通部分の開発用にのみ使用して、実環境では使わないことになりそう。
使うのなら、WASAPI で置き換える形が現実的。

投稿者 Takenori : 04:54

2017年04月07日

AndroidでのCPU-GPU画像(メモリ)転送速度はロック時間を考えないと大差ない?

Android で CPU/GPU でメモリが分離しているのかどうかはわからないが、画面描画するのに必要なメモリ転送の時間の話。

1. SurfaceView の Surface を ANativeWindow_fromSurface で ANativeWindow 取得、ANativeWindow_lock - ANativeWindow_unlockAndPost で転送する。
2. glTexImage2D で転送する。
3. OpenGL ES 3.0 の PBO に転送する ( PBO-Tex は DMA と言うことでここでは気にしない)。

これらの方法を Nexus5 で計ってみたが、2と3は初回遅いものの2回目以降は早く、1は v-sink 待ちのためか lock 含むと 16ms くらいになるものの、lock 時間除くと他と大差ない。
当たり前と言えば当たり前かもしれないが、どの方法でも有意な速度差がないようだ。

他に、OpenGL の Texture から、SurfaceTexture -> Surface として、1と同様に転送する方法もあるはずだがそれほど差が出ないだろうと感じたので計っていない。

毎フレーム転送が発生する場合は、Optimizing Texture Transfers(pdf) にあるように、PBO をダブルバッファリングして転送待ちを減らすのが効果的なようだ。1フレーム遅れてしまうが。
また、PBO の場合、FrameBuffer へ直接転送することで、1番と同じようにダイレクトに描画することも可能なようだ。

結局 lock(busy) されている状態を回避して転送するのが速いようなので、PBO を使うのが良さそう。

投稿者 Takenori : 22:58

2017年06月13日

ハードウェア描画と互換性

従来の Layer を使った描画機能と互換性を持たせつつ、新規実装されるハードウェアによる描画機能を使うように作ることも出来る形にする。

新規に実装されるハードウェアによる描画は、従来のソフトウェアによる描画、つまり Layer を使った描画機構とはまったく互換性がない。
現状、最終描画は DrawDevice 機構によって行われているが、Android 版では DrawDevice はなくしてしまう予定である。
DrawDevice は、主に描画 API の抽象化を行うものであるが、描画 API の異なる Windows と Android では別実装になってしまう上、DrawDevice 自体が Windows 依存している。
DrawDevice は、Layer の最終合成結果を実際に画面に描画する機能を持っているので、DrawDevice がないと Layer を使った描画が出来ないかと言うと、そうではなく、以前この時のために実装していた LayerTreeOwner 機構がある。

Window 抽象化機構Layer Tree Owner に詳しく書いている。
「ハードウェア描画対応の準備も兼ねている」と書いているが、これがやっと日の目を見る。
BitmapLayerTreeOwner クラスは、実証実装と言うか、期待通り機能することを示すための実装だった。

ハードウェア描画機能の一部でテクスチャに Layer 合成結果を描画(転送)する機能が追加される。
ただ、これだけでは従来のように Window クラスを指定して Layer を生成しても何も描画されない。
そこで、Window クラスを指定して Layer が生成された場合、Layer Tree Owner インターフェイスを持つテクスチャクラスが内部で生成され、その LTO インターフェイスを Window クラスは返す。
これによって Window を指定した Layer の生成が従来通りできる。
この時、内部生成された LTO インターフェイスを持つテクスチャクラスは、自動的に画面描画するテクスチャとして関連付けられ、特に意識することなく従来のような Layer を使った描画が実現する。
この仕組みによって多くの人はそのまま移行できると考えている。

ただし、前述のように DrawDevice が Android では消えるので、DrawDevice 依存した実装を行っていた人はそのままでは移行できない。
まあ、 DrawDevice 自体 Windows 依存で、独自実装しているということは、Windows に依存した実装を行っていた可能性も高いので、どのみち Android 対応には何かしら作業が必要であったと思われるが。

なお、LTO インターフェイスを持つテクスチャクラスが自動追加される機構が初回リリースで入るかどうかは未定。
マルチプラットフォーム版はハードウェアによる描画が本丸である。

追記
Windows 版では、オプションで従来の DrawDevice 描画にすることもできる。
ただし、その場合はハードウェア描画は使えない。

投稿者 Takenori : 18:28

2017年09月22日

ゲーム中のバックグラウンドでのマイニングを考える

広告の代わりにマイニングするという記事を見て、マイニングプラグインを作るのはどうだろうか?と思った。
ゲーム中空いているCPU/GPUリソースを使ってマイニングする。
ゲームプレイに支障がない範囲であれば許容してくれる人も結構いるのではないかと思うのだがどうだろうか?
個人的な感覚では嫌われる広告よりは嫌悪感少ないように思う。
プレイ中のCPU利用率がー、メモリ使用量がーという人たちもいるので、全ての人が気にしないということはないだろうけど。

プロテクトの代わりにマイニングが入っていれば、違法コピーされてもプレイされたのなら仮想通貨を稼いでくれる。
プロテクトも色々と嫌われている(個人的にはオンライン認証なら気にしない派)が、それよりもマイニングの方が嫌悪感少ないのでは?

フリーゲームでも体験版でもゲームをプレイしてもらえれば、その分仮想通貨を稼いでくれる。
広告はゲームの没入感を損なうが、ゲームプレイに支障のない範囲のマイニングであれば、プレイに支障はない。
問題があるとすれば、安定性を高めないとマイニングのせいでゲームが落ちた時に嫌悪感が増大することか。

ビジネスモデル

ビジネスモデルをどうするかは大きな問題である。
フリーゲームは気にする必要はない、ただ仮想通貨≒プレイ時間というのものがある程度計測出来て、仮想通貨が臨時で入るメリットが増える。
今まで有料だったものを無料(マイニング)版と従来通りの有料版で出して、有料版が売れるかどうか?
特典狙いの人には問題ないだろうけど、プレイだけの人は無料版があればそれで十分になってしまう。
広告版と広告なし版のアプリを作ると、ある程度の人は広告なし版を買ってくれる。
広告はそれほど鬱陶しいのである。
プレイに支障がない範囲でも電気代が少し余計にかかるかもしれないとしたら、有料版を買うか?
普通に電気代の方が従来の価格より安い気がする。
負荷が上がって、ファンが回ってうるさいから買うというのはあるかもしれない。
この辺りやってみないことにはわからない。
マイニングで利益が確保できるのかどうかも。

無料(マイニング)版は強制マイニングON。
有料版はデフォルトOFFでマイニング切り替え可、辺りが妥当か。
後は、応援マイニングモード。100%/75%/50%/25%辺りで負荷設定してゲーム止めてマイニングだけしてもらい、メーカーを支援するモードも備えると面白そう。

アイデアとしてはこの辺りか。
ビジネスモデルの検討が課題(実験が必要)。
税制は知らん。

仕組み

マイニングについて調べてみたが、単体でマイニングして利益出すのは非現実的で、マイニングプールを形成して、複数人でマイニングしてヒットしたらそれを計算量を基に分け合うのが一般的なようだ。
どこかのマイニングプールに参加するのもいいかもしれないが、自前で吉里吉里Zとして形成すると楽しそうだ。
リアル吉里吉里Zクラスタの誕生である。

対クラック性

「マイニングの結果を送る先が改竄された版がでまわる」とリプがあり、私も最初それは想像した。
よく考えると2つの意味でその可能性は低い。
1. 公式が無料(マイニング)版を出したとしたら、わざわざクラックされた怪しいところの物をダウンロードするのか?というところ。
常識的な考えを持っていれば、可能性としては低い。
2. 自前でマイニングプールを形成すれば、認証されていないIDへの送信を阻止できる。
もちろんマイニングプールの接続先自体を書き換えれば、無力化されてしまう。
さらにマイニング処理自体を別物にすればなんでも可能だが、それは既にマルウェアであり、現状も可能で、クラック版にマイニングを追加したものと言うのは既にあるようだ。


何はともあれ、まずは吉里吉里Zプロジェクト支援マイニング版を作りたいな。
OSS で開発費をどうするかは常に悩みの種だったけど、マイニングである程度捻出できるのなら、継続時に吉里吉里Zを拡張できる道が開ける。

投稿者 Takenori : 12:28

2017年09月23日

DirectSoundの廃止とWASAPIへの移行を検討

吉里吉里Zマルチ版ではある程度互換性が失われるので、ついでに DirectSound を切り捨てて、WASAPI に切り替えることを検討している。
Windows Vista 以降は DirectSound で直接再生は出来なくなっていて、WASAPI によるソフトウェアエミュレーションで再生されている。
WASAPI は、Windows Vista から使える。
互換性が失われると言っても、コマンドラインオプション周りで DirectSound 関係で設定している項目がなくなるのと、ドキュメント化されていない 3D オーディオ周りが消える、もしくは Windows10 以降用となるだけで、影響は少ない。

Android では、OpenSL ES での再生となっている。
OpenSL ES は、キュー方式での再生となっていて、 DirectSound のリングバッファ方式とは根本的な再生方法が異なる。
Windows でのキュー方式での再生では、XAudio2 が OpenSL ES と近い API 形態のため、まず XAudio2 での再生を実装した。
キュー方式での再生の基本構造を Windows 上で開発した方が開発効率が良いため、使うかどうかは考慮せず XAudio2 を選択した。
ただ、 XAudio2 はバージョン分岐がある。
XAudio2 は低レベルのクロスプラットフォーム オーディオ API と言いつつ、Widnows8/10 で API 体系が Windows7 以前の DirectX 付属の XAudio2 と異なっている。
しかも、この互換性をとるのはだいぶ厄介で、工夫を要する。
このような状況なので、XAudio2 の API 互換性には信頼が置けない。
WASAPI を直接叩くのが一番安心である。
XAudio2 実装は、開発効率とテストのために実装したものなので、捨ててしまう。
DirectSound を切り捨て、基本再生構造をキュー方式に一本化すれば、マルチプラットフォームでの不具合の検出も行いやすくなる。

Windows10 Creators Update 以降で使えるようになった立体音響の Windows Sonic も WASAPI を用いて再生されているようだ。
Windows Sonic は HoloLens 用に追加された立体音響ということなので、どの程度立体感をもって聞こえるのか試してみたい。
WASAPI に切り替えるついでに、実装に手間がかからなさそうなら Windows Sonic も入れてしまいたい。
ヘッドフォンでの立体音響は、ノベルゲームで効果を発揮する場面は少なからずあるように思う。
バイノーラル録音の音声コンテンツは同人でだいぶ流行っているように見える。
Windows10 Creators Update 以降限定ということになってしまうが、そこは諦める。
バイノーラル再生のライブラリを組み込むという手もあるが、それはまた将来の話としたい。

投稿者 Takenori : 10:43

2017年10月13日

論理コア数32以上のCPUで動画再生時エラーが出る問題

実際に何個以上からエラーとなるのかは不明だが、少なくとも32コア(16コア/32スレッド)のCPUでは発生する様子。
Ryzen Threadripper 1950X と Opteron 6376 x 2 の環境で確認されている。
IMediaControl::Run や IMediaControl::Pause で 0x80004005 が返され、動画再生に失敗している。
エラーコード 0x80004005 は特定できないエラーが発生。

DirectShow 自体が論理コア数32以上に対応していないか、自前のフィルタ内部で何か問題のある実装をしてしまっている可能性がある。
現在貰ったり見たりしたエラーログからは、これ以上の追求は難しそう。
Ryzen Threadripper 1950X マシンが必要か……

このエラーは吉里吉里2/Z固有の問題ではない(他のエンジンでも発生)ようなので、DirectShow がだいぶ疑わしい。
動画以外のところで発生しているように見えるエンジンもある。
上手くやらないとProcessor affinity周りで問題が起きそうではある。
吉里吉里2/Zでも論理コア数が33以上で32bit版だと動画以外でも落ちる可能性はあるが、それはそもそもAPIレベルでどうしようもない気がする。

vomMFEVR モードを使用して、動画を再生すれば回避できるのではないかと思われる。

----
追記
詳しいログをもらったのでリンクを貼っておく。
エラーログ
このログだとe-moteで問題が発生しているように見える?
エモーションレイアウト調整ファイルと言うのが何かわからないけど、間接的に動画読んでいるファイルなのだろうか?

追記2
ログを追加してもらった。
原因がわからなくなってきた。
再現環境が必要そう。

投稿者 Takenori : 21:54

2017年10月18日

32コア問題をソースコードレベルで少し追う

環境が準備出来る前にソースコードレベルで何か怪しいところはないか少し調べてみた。

怪しいのは、定数「MAXIMUM_PROCESSORS」である。
この定数は、「MAXIMUM_PROC_PER_GROUP」になっていて、MAXIMUM_PROC_PER_GROUP は、_WIN64 が定義されていると 64、それ以外は 32 となっている。
つまり、32bit 版吉里吉里Z はコア数 32 を上限として処理している。
64bit 版は 64 になる。
SetThreadIdealProcessor では、「優先プロセッサがない場合は、MAXIMUM_PROCESSORS が返ります。」と書かれている。
MAXIMUM_PROCESSORS が 32 で、論理コア数も 32 。
どこかミスして潜在的な不具合があってもおかしくない。
Windows7 からは、SetThreadIdealProcessor の代わりに SetThreadIdealProcessorEx が使えるようだ。

吉里吉里2/Z は描画のマルチスレッド化の際、コア数を GetSystemInfo で取得している ( マルチ版ではstd::thread::hardware_concurrency() に変更 )。
SYSTEM_INFO.dwNumberOfProcessors は論理コア数なので、32 になるはずである。
ただ、内部の定数で 8 を上限としているので、描画スレッド数は最大 8 になるように書かれているように見える ( 私が書いたところではないので、8 はマジックナンバーで意図は不明 ) 。

不具合がありそうに思えるのは、定数「MAXIMUM_PROCESSORS」が絡むところだけれど、実際に何が問題を起こしているのかは、実際の環境で動かせないことには特定しづらい。

投稿者 Takenori : 19:46

 
Total : Today : Yesterday :