W.Deeの2007年4月の日記

kikyou.info»日記
最新月 : 2008年10月
2003年 [             3    4    5    6    7    8    9   10   11   12  ] 月
2004年 [   1    2    3    4    5    6    7    8    9   10   11   12  ] 月
2005年 [   1    2    3    4    5    6    7    8    9   10   11   12  ] 月
2006年 [   1    2    3    4    5    6    7    8    9   10   11   12  ] 月
2007年 [   1    2    3    4    5    6    7    8    9   10   11   12  ] 月
2008年 [   1    2    3    4    5    6    7    8    9   10   11   12  ] 月
2009年 [   1    2    3    4    5    6    7    8    9   10   11       ] 月
前月の日記  次月の日記

2007年4月16日

吉里吉里2の新しいフルスクリーン解像度決定アルゴリズム

吉里吉里2の最新の開発版では、新しいフルスクリーン解像度決定のアルゴリズムが搭載されています。

これは、変な(非標準の)解像度をプログラム側で設定してもフルスクリーン表示が可能になったり、アスペクト比を保持したままでの拡大表示ができない液晶モニタでのアスペクト比を保持したままでのフルスクリーン表示を可能にするものです。以前のバージョン(2.28など)でも、アスペクト比を保持したまま拡大ができない液晶モニタなどのために、フルスクリーン時の画面解像度を変えずにエンジン側で拡大を行うようにする設定があります)

決定アルゴリズムにはいくつか動作モードがあるのですが、デフォルトの「自動」は液晶モニタ向けの設定になっています (CRTでもほとんどの場合、問題はないと思います)。これはOSから画面モードの一覧を取得してその中から解像度を選ぶのですが、アスペクト比を保持できる画面モードのうち、アプリケーション側で設定した解像度と一致する解像度があればそれを使います。そうでなければエンジン側で拡大表示を行います。モニタ側で拡大してさらにエンジン側でも拡大すると画像が汚くなるため、モニタ側での拡大か、エンジン側での拡大かどちらか一方だけを使うようになっています。

そのほか、画面解像度を変えないモードや、アスペクト比が保持されない解像度も選択肢に入れるモード(CRTや、アスペクト比を保持したままでの拡大表示が可能なモニタ向けのモード)があります。「エンジン設定」でこれらの設定を変えることができますが、通常の使用ではデフォルトの「自動」で問題ないと思います。

皆さんも是非、お使いのモニタとお手持ちの作品でちゃんとフルスクリーンになるかを試して頂けると幸いです。フルスクリーンにしようとすると、解像度決定の際の内部的な情報がデバッグコンソールに表示されますので見てみてください。

それにしてもうちの液晶モニタは1920x1200ですが、うちのグラフィックカードとの組み合わせ?では、アスペクト比が同じモードとして 1440x900や1680x1050, 640x400, 320x200 しかデフォルトでは候補に出てきません。よくゲームなどで使われる 800x600 などの解像度ではちょうどフィットする解像度がないため、デフォルトでは常にエンジン側での拡大になります。

あと解像度リストをみてて思ったこと。いまのモニタは 1920x1200 だけれども PC-9801の「高解像度モード」であるところの 640x400ってこれと同じアスペクト比 (8:5) なのね。なんと時代を先取りしたワイド解像度仕様だったということですか。

吉里吉里2の新しい描画モデル

2.29-20070416 (開発版の吉里吉里2)を公開しました。

描画モデルというと大げさなのですが、吉里吉里の表示機構に新しい方式を搭載した初めてのバージョンです。

吉里吉里がレイヤを演算して最終的に画面に表示する部分を抽象化し、ここを置き換えることができるようになっています。

Window クラスに drawDevice というプロパティが追加されていて、ここに描画デバイスのインスタンスを設定すると、その描画デバイスを使用して画像を描画するようになります。デフォルトでは「PassThroughDrawDevice」という、従来の吉里吉里と全く同じ動作をする描画デバイスが指定されています。なので、特に何もしない場合は「従来の吉里吉里と全く動作が変わらない」で正解です。

描画デバイスを用いる利点は、吉里吉里のウィンドウへの描画とユーザからの入力全般を乗っ取ることができるので、たとえばハードウェアを用いた描画を実装してより高度な表現をすることができるようになると言ったことでしょう。本体側でこれを使っていろいろな描画方式に対応するようにする予定はありませんが、この機構に対応したプラグインを作成できますので、自由に拡張することができます。プラグインのサンプルは https://sv.kikyou.info/trac/kirikiri/browser/kirikiri2/trunk/kirikiri2/src/plugins/win32/drawdevice にあります (これは吉里吉里のデフォルトの PassThroughDrawDevice を単純にプラグインの形にした物 )。

2007年4月5日

Risse進捗(17)

関数は、最後にreturnを書かなくとも、関数の終わりに到達すると自動的に呼び出し元に戻りますが、この際に、最後に評価した文や式の値を返すようにしました。

これにより、たとえばいままで

function add(x, y) { return x + y }

と書いていた物を単に

function add(x, y) { x + y }

と書けるようになります。x + y が、関数から戻る際に最後に評価した値ということになりますから、x + y の結果が戻ることになります。

文や式の値、と書きましたが、式だけでなく、文も値を持っています。

たとえばif(X) {A} else {B}という文は、X?A:Bと書くのと同じで、生成されるコードもまったく同一になります。

またswitch文は値付きbreakの値を返しますから、

function f(x) {
  switch(x) {
  case 0: break "A";
  case 1: break "B";
  case 2: break "C";
  }
}

のような書き方ができます。まぁ素直にbreak遣わずにreturn "A"とか書いた方がいいような気もしますが。

実験的に()の中にブロックが書けるようになりました。

return ({var sum = 0; rr.each() { |e| sum += e }; sum })

まるでGNU Cの拡張文法のようですが、こんな書き方をするぐらいならば素直に () の外に書いた方がいいと思いますし、あまり決定的に便利な用途が浮かびません。Risseにプリプロセッサ・マクロがあれば少しは役に立ちそうな気がしますが、その予定も今のところありませんし。なので将来的にはこの機能は取り外すかもしれません。

PerlやShellスクリプト、Ruby、Pythonなど、名だたるスクリプト言語の多くは $_ や _ といった変数を持っていますが、今のところRisseにはありません。

で、本題と言うかなんというか。

最後に評価した文や式の値を関数が返すのは、なにもreturnを書きたくない、ものぐさな人向けの機能だけではなくて、evalを容易にするための布石でもあります。実はこっちの利点の方が大きいと思っています。evalはこれから実装します。

Risseは、たとえばC言語のようにmain関数からプログラムが実行されるということはなくて、関数などを用意しなくても、スクリプトに実行したい内容をいきなり書けばそれが頭から実行されます。実はRisseではこのような、一見すべての関数の外側にあり、どの関数にも属していないように見える部分でも、内部的にはさらにそれを覆う関数を一つ作って、実行の際にその関数を呼ぶことでスクリプトを実行しています。

たとえばスクリプトとして

System.getTickCount()

が与えられれば、内部的にはこの外側に無名の関数が一つあるかのように解釈されます。

function () {
  System.getTickCount()
}

外側にあるのは関数ですから、下記のようにreturn文で戻ることもできます。

return System.getTickCount()

ここでおわかりかと思いますが、ちゃんとスクリプト全体の評価結果にも「戻り値」があります。たとえば、上記の場合、System.getTickCount() の戻り値がスクリプト全体の戻り値になります。evalの戻り値というのは、このスクリプト全体の戻り値ということになります。

TJS2の場合、文と式は厳密に区別されていました。式が来るべき所に文が来ると文法エラーになりますし、文が来るべきところに式がきても文法エラーになることがありました。なので、evalも2種類あり、式のevalと文(スクリプト)のevalが分かれていました。また、値を返すためには return が必須でした。

Risseの場合、たとえば上記の System.getTickCount() は一応式に分類される物ですが、returnを書いて「文」にしなくても値を返すことができるようになりました。

つまり、

eval("System.getTickCount()")
eval("return System.getTickCount()")
eval("var ret = System.getTickCount();
      return ret;")

は、どれもSystem.getTickCount()の戻り値を返す動作をするということになります。

eval("for(var i = 0; i < 5; i++) click()")

のように、evalしても結果が有用な値になりそうもない場合もありますが、そうであれば単にevalの結果を捨てればいいだけの話になります。

式を評価したい場合も、文を評価したい場合も、複数の文を含んだスクリプトを評価したい場合も、すべて一つのevalで対応できるようになったと言うことになります。