プログラミングにまつわることで、思い出したこと、考えたこと、気になること
など、ともかく低レベルでもみっともなくても中途半端でいいからメモを取ろう、
と思うページ。
分類とかは後で、別にホームなりからインデックスを用意すればいいや、だし、
気力があれば内容の修正もすればいいんだし。
体系立てようとか、カッコ悪くしないようにとか、余計なことを考えていると
一向に書けなくなるのだった。
過去ページは、
で、たいはんはネタごとにホームからリンクしなおしている。
結局、前回から間があきすぎ。気をつけないと
(といいつつ、とりあえずの場繋ぎネタ)。
自前のstring.hとかを作ったときに書いていたけれどアップしていなかった
strtol/strtoul ルーチンがあったので出しておきます。
ほんのちょっとだけれど、コンパイラ付属のやつよりか速かったので、
自分的にはうれしかったりする。
単にテストプログラムの傾向のせいかもしれないとしても。
己版のstrtolでの、コンパイラごとの差ってのが コンパイラのオプティマイズ能力の差ってことになるだろうけど (いやテストに使った他のライブラリ関数の性能も影響するか)、 bcc32は、まあ、これに限らずasmソースを吐き出さしてみたりすると、 ちとがっかりするような(昔ながらの)モノだけれど、 この程度の速度差なら別に目くじら立てるほどでもないなあ、 って気もする(もち用途しだいだけれど)。
コンパイラ 標準 拙作 bcc32 v5.5 (-Ox -d) 47秒 28秒 vc6 (/Ox /ML) 30秒 27秒 Mingw 2.95 (-O3) 30秒 27秒
どちらかというと、bcc32のコンパイラ付属版の遅さが目立つ。
テスト結果はテスト故の呼出頻度なんで、
実用上はたいして問題ないだろうけど。
手持ちの古い borland-c v5 付属のstrtolのライブラリ・ソースをみると、
ちとへんに考えすぎなんじゃないかいなあ、って気がしないでもない。
ルーチン追加したら、やっぱ、こまめに確認しないと駄目っすね。
大量にまとめて変更加えてしまってからバグると些細なバグ取るのも
たいへん……ってわかっていても、つい時間がないからって不精すると
1日2日なんかすぐ使ってしまう(T T)
1つは以前に書いた strupr(または strlwr) だったんですが、
*s++ = TOUPPER(*s);
なんて書いてたら、みごとに副作用……以前の(簡単な)チェックでは
通ったし左辺なんで(実行順序確定してるから)大丈夫と思ってたんですが(未確認)、
SHCでは駄目で 頭一バイトがなくなってしまうルーチンになって
しまってました(オプティマイズに関係なく)。
確認のためにアセンブラ生成してみれば確かに代入の前に
インクリメント。
なまじ、ほかのコンパイラでチェックしてただけに中々疑わないでやんの。
デバッガさまさまだわ。けど、なさけない……。
で、アセンブラ・ソースみてて、unsigned char * のポイント先からの ロードでゼロ符合拡張が不用な時でも生成されてるのを見て悲しくなる (gcc だともうちょい大丈夫だったような気がするなあ)。 やっぱし基本は char* にして必要なとこだけキャストしたほうがよさそうか。 char 型がunsigned/signed かは CPU にとって扱いが有利な ほうが設定されているものと想定して。互換性の都合でsigned のことが 多そうだけれど(昔ながらの8/16ビットCPUとかunsignedのほうが得意だとしても)、 よりネイティブなほうをコンパイラオプションで指定しとくとする、と (もっともstring.c等を書き直す気力が……)。
■アドベンチャでの立ちキャラ/バストアップのジャギ対策やクロスフェードとかですが、 やっぱり、ほんまもんのαブレンドが使えると楽チンですね (描画の頂点カラーでα指定できちゃうと)。
■αブレンディングは半透明率みたいなもんで、
例えば α=0〜255(透明〜不透明) のとき
αブレンディングでの描画は
下になる絵:コレから表示する(上になる)絵 = 255−α:α
となる比率で半透明で描画することになります (αの値の意味が逆とか比率も逆とか128で100%になるのとか単純な比でない合成とかハードや指定によりけり なんですが……説明としては255でなく実数1.0で一般化したほうが良い面もあるだろうけれど、とりあえず)。
ハードでのαブレンドのサポートとしては、
の2つのがあります。
□テクスチャデータにαが使える場合の立ちキャラ/バストアップは、 透明(抜き)色になる部分はα=0、絵の本体はα=255、透明色と絵の境は アンチエイリアスのためにα=1〜254、といった具合の絵になります (A4R4G4B4なテクスチャだと α=0〜15 で同様に)。 テクスチャデータにαが使えない場合は、たいがいは、 描画時に特定の色(0:黒だったりユーザ指定だったり)を描画しないですます 透明色として指定ができるでしょう(ハードでするにしろソフトでするにしろ ゲームなどで用いる場合)。
□立ちキャラのポーズ替えなんかはそういった2枚の絵を、 前から表示されてた古いほうは不透明から(半透明を経て)透明へ、 新しいポーズ絵は古い絵の手前に、透明から透明から不透明へ、 だいたい同じ時間をかけて α変化させて表示(描画)することで行えます。 古い絵は透明色になった時点で捨てます。
ただ、これで表情替え(抜き色/半透明/不透明領域の形が全く一緒の画像で 不透明領域の中の絵が一部書き換わっているもの)の場合に上記のやり方を すると、表情が変わっている間、絵の明るさが変動する (暗くなる…上手くタイミングが合えば微妙な変動だろうけど)ので、 見た目はあまりよろしくないです(好みの類にも思うけど)。
で、表情替えのときはちと方法を変えて、 古い絵はそのままで、新しい表情の絵だけ、手前に表示して 透明から不透明へα変動させていき、不透明になった時点で 下に隠れてしまった古い絵の表示をやめる、と、いうふうに してやります(これだと、なんとなく、表情が動いているように見えたりしますし)。
□問題は、この使い分けをどこで誰がするか、なんですけど……
アドベンチャだとシナリオ・スクリプトで専用命令なりオプションなりを用意して
使い分けてもらう、ってのがプログラム的には手間は少なくてすむし、
責任はスクリプト書きに押し付けちゃえて安全かもしれません(笑)。
でも、スクリプト書く人が事情を理解してくれない人だったり
勘違いしちゃう人だと、間違った命令を使われ続けちゃうかもで、
いい人に当たれば、ですが。
ポーズ替え用の命令で表情替えする分にはまだいいけれど、
表情替えの命令でポーズ替えをやられたら……人の作品(ゲーム)遊んでいて、
そういうの見ると結構悲しいもんです。
スクリプト打ちの手間を減らすならば、データ管理用のテーブルで
依存関係を記述してプログラムで対処、ってのも手かもしれません。
データ管理自体も他人(グラフィッカーさん)に頼めるならば
頼んでしまいたいですが
(.csv形式のデータでやりとりするツール用意したりとかになる)。
■で、まあ、最近の機種は、αブレンド機能が当たり前のようについているので
楽なんですが、古いのだと出来るけど、いろいろ制約があったりする。
そのうち R3000 な某機は、他(SH2*2な某機とか)よりは比較的よいんだけれど、
ちと面倒は面倒で……
□αブレンディング自体はなく、
ただ通常描画以外に4種類の特殊な描画方法が選べるようになっています。
テクスチャの色/ピクセルはRGB各5ビット+特殊描画用フラグ1ビットの
計16ビットで、値 0は透明色、特殊ビットが立っていれば特殊描画可能で
立っていなければ(何か指定があっても)通常描画のみ、
また、描画時は頂点カラー(RGB)が指定できるとなっています。
特殊ビットが立っているピクセルに対しては通常の描画以外に、
下地の絵 50% :描画する絵 50% 50%のαブレンド 下地の絵 100% :描画する絵 100% 飽和加算で対等に足す 下地の絵 100% :描画する絵-100% 飽和減算で描画するピクセルの値を引く 下地の絵 100% :描画する絵 25% 飽和加算で描画するピクセルの25%を足すという描画が行えるとなっています (飽和加算は足した結果が上限値以上になるなら上限値で打ち止め、 飽和減算は引いた結果が0未満になるなら0で打ち止め、になるような処理です)。
・RGB(31*0.50+12*0.50, 15*0.50+12*0.50, 7*0.50+12*0.50) → RGB(21,13, 9) ・RGB(31*1.00+12*1.00, 15*1.00+12*1.00, 7*1.00+12*1.00) → RGB(31,27,19) ・RGB(31*1.00-12*1.00, 15*1.00-12*1.00, 7*1.00-12*1.00) → RGB(19, 3, 0) ・RGB(31*1.00+12*0.25, 15*1.00+12*0.25, 7*1.00+12*0.25) → RGB(31,19,11)といった具合です。
一見しただけでは、固定%で、どうすりゃええねん、って気もしてきますが:-)、 実際に人が(ソースで)やってること見ると結構納得だったり (ちゃんと自力で思いつける人は世に何人もいるだろうけど、己は^^;)。 描画で頂点カラーが指定できる、ってのがミソだったんですね。
とりあえず、αブレンドもどきの描画方法ですが、
これで、だいたい希望するα位の半透明な画像が描画できます。
モドキなのは、下地(背景)から明るさをへつるときに、
本物なら描画する色によってその値のα分をへつることになりますが、
モドキでは一律最大値(真っ白)のα分をへつるので他の色からすれば
下地をへつりすぎてしまい、結果、暗くなる、っということです。
例えば下RGB(255,128,64)と上RGB(128,128,128)をαが60%で合成した場合、CLUT付画ならばパレットをもう一本用意するだけなので 容量的には問題ないですが、 ただでさえ遅い半透明描画を2回行わないといけないので 速度のほうは気にしないと駄目な場合が増えるかもしれません。
本物:RGB(255*0.4+128*0.6,128*0.4+128*0.6, 64*0.4+128*0.6)
→ RGB(178,128,102) モドキ:RGB((255-255*0.6)+128*0.6, (128-255*0.6)+128*0.6, (64-255*0.6)+128*0.6)
→ RGB(178,76,76)
■さて、バストアップの縁にアンチエイリアスのために半透明を置きたい、
とした場合どうしましょうか。
フェードを行わないならば 下50%+上50% で半透明を置くのがいいのですが、
今時のゲームの立ちキャラでフェードしないのも
(いや、企画レベルから表現スタイルを固めてりゃいいんだろうけど)……
フェード速度をはやめにして
誤魔化してフェード中は縁処理しない、とか?
……いえいえ、誤魔化せません(でした^^;)。
めだってしまうので、それなら縁処理はしないほうがましでしょう。
己は挫折したので、以下は人に聞いた方法:-)。256色画を対象に考えます。
と、いう具合に、プログラム的には最初のαブレンドもどきの改良版と いった感じですみます。問題は、データをどうやって作るかですね。 グラフィッカーさんにがんばってもらう、ってのがプログラマ負担は少ない (実際そうだったことあるし^^;..けどコストかかりすぎになるかも)。
プログラマがツールを作るとしたら、
といった感じでしょうか。 己自身は実際にはツールを作っていないので (別の機種でハイカラに変更なったんで必要がなくなった) 考えてただけなんですが、 やるとしたら後の方法を思ってました。
減色プログラムは凝り出すと泥沼にハマリますし、 すでにOCTPiX(市販)やPadie(フリーソフト)のような質の高い 減色ツールがあり、要求されるクオリティを思うと がんばって到達できるか、とか、できるとしても時間を思うと、 基本はそれらに任してしまい、縁の部分だけ自前でやるのが無難かな、と。
縁の処理は、縁に相当する部分のピクセルだけをサンプルしてそれを 残りの色数15〜55色なりに(α付きで)減色することになりますが、 (クオリティ求め出すと)ただの減色以上に頭痛いので適当に端折り、 サンプルするときに一定輝度以下の点のみを対象にしたり、黒や焦茶系 であることに依存して単色でα15階調とか、あるいはαを4なりの数階調として 色の代表値取得するとか、いろいろ考えられます。 それでも考えてると頭痛いんで、専用エディタがあるならドッターさんに 目で見ながらがんばって貰うのは正解かもって気も…(恨まれるな)。
と、書いたけれど、プロ向けなOCTPiXや FARLUX とかなら α付の減色やもろターゲット向けな減色ができるらしいんで? 持ってるトコならそんな苦労する必要ないでしょうね。
でもって、どんなに苦労してもユーザには、高解像度でα使える機種の 画と比べて汚いないとか思われちゃうもんかも^^;)。
ゲームなどで比較的低い画面解像度でメッセージなどの文字を表示する場合、 ドットのガクガクを減らしたり字の潰れ具合を軽減するために、 フォントデータを2値でなく4階調や16階調やそれ以上の階調の データを用意して表示したりします。
けれど、せっかく階調のある文字フォントを使っているのに、 黒バックならばきれい見えるけれど 少し明るい場所に表示すると 字の縁にまばらにつぶつぶと黒いドットがみえて 汚らしく見えてしまっているソフトが、たまにあったりします (もちろん、そうでないモノが多いですが)。
ピクセルデータにαが使えるならばジャギになりそうな箇所にαを 用いたり某R3000な機種で白文字ならば100%の飽和加算で表示(※1)、 というのも手ですが、α/半透明が使えなくても、そこそこ綺麗に 見せれます。
で、どうやるか、ってと……単に、下地のだいたいの明るさから 字自体の明るさまでの濃淡にする、ってだけです^^;
文字フォントデータがCLUT有りで描画可能なら、 背景の大体の色から文字の色でグラデしたようなパレットを用意 したりCLUT生成ルーチンを用意すればいいってだけです (濃淡の差によって線の太さが変わって見えてしまうこともあるけれど、気にしないことにする、と)。
例えば(アドベンチャゲームなんかで)半透明なメッセージウィンドウ内に 白文字を表示する場合、 ピクセルの各R,G,Bが8ビットで0〜0xFFだったとして、メッセージウィンドウを 半透明率α50%で黒地RGB(0,0,0)を描画(下地の色の明るさを半分にする)とすると、 その範囲の背景は一番明るい白RGB(0xFF,0xFF,0xFF)でも RGB(0x80,0x80,0x80)になるので、 文字フォント・データは明るさ 0x80〜0xFF にして表示すれば、 黒プチに化けることなく そこそこ綺麗に見えます。
実際の下地の明るさ/半透明具合にもよるけれど、 どうせ手を抜くなら 0x00〜0xFF よりも 0x80〜0xFF (というか値の半分の範囲)の明るさでフォントを作るのが楽でよいです。 下地が暗い分には(黒RGB(0,0,0)でも)まま大丈夫なんで、使い回し易いですし。
文字の色換えについては、CLUTか描画時の頂点カラーなりで 調整することになるかな。 場合によっては VRAM へテクスチャを転送する直前に変換をかけるのも手 だし。
※1 半透明ウィンドウの上に100%飽和加算のみで白文字を表示するのは あまりよい手ではないかも。 半透明なので白文字の白の薄い部分に下地の色が混ざってしまい、 色や模様の混ざり具合によっては汚く感じたり(バグに思われたり)、 下地の色が明るいと線の太さが変わってみえやすかったり 文字がつぶれやすかったりで。