Hatena::ブログ(Diary)

Ko-Taのバ・ー・ルのようなもの

2014-08-03

ノートPCのタッチパッドにおけるホイール処理

ノートPCについているキーボード下のタッチパッドにおけるマウスホイール処理についてメモしておきたいと思います。

実は難物なんですこれ・・・。


イベント内容

パッドを使ったホイールスクロールの場合は、マウスによるホイールスクロールとは異なり、特殊な数値のイベントが飛んでくるので、処理やインターフェイスの根本的な見直しが必要になります。

・マウスによるホイール
MouseWheel(WheelDelta:-120) 230ms
MouseWheel(WheelDelta:-120) 102ms
MouseWheel(WheelDelta:-120) 85ms
MouseWheel(WheelDelta:-120) 123ms

・ノートPCのパッドによるホイール
MouseWheel(WheelDelta:-14) 12ms
MouseWheel(WheelDelta:-10) 10ms
MouseWheel(WheelDelta:-8) 13ms
MouseWheel(WheelDelta:-9) 8ms
・・・

マウスのホイールでは上下に1回2回といったグリッド間隔による回数によってイベントが発生していますが、パッドの場合はもっと細かい単位(ピクセル)の連続したイベントが飛んできます。

また、デバイスの設定によって離した後のイージングも発生します。

(イージングを判定するコードは見つけられませんでした。判別出来るか不明)


と、こんな違いがありますので、対応処理が必要です。

まじめに対応すると場合は、プログラム的(イベント処理)な対応と、GUI(グラフィックインターフェイス)の両方が必要になります。


対応しないとどうなるの

対応していないからと言って、そこまで深刻なバグが発生するわけではありません。

よくある実害が、パッドでスクロールさせると超高速でスクロールするぐらいです。

上記の通り、スクロールイベントが細切れで大量に飛んでくるのが原因です。


対応 - イベント処理

パッドによるイベントは、間隔が非常に狭いため、Wheel値をポーリング処理(ゲームの1frame単位で値を取得して処理)で取得している場合はかならず抜けオチが発生します。

抜けオチが発生すると、スクロールする移動量が一定で無くなります。(早くスクロールしたのに遅かったり、逆になったり)

なので、イベントから値を取得し、WheelDelta値は加算、累積しておく必要があります。


対応 - GUI(グラフィックインターフェイス)

大変なのがこれ(GUI)です。

デザインそのものから見直す場合もありますので、昔の作品をプログラムを弄って対応…と単純にはいかないでしょう。


簡潔に言ってしまえば、GUIをピクセル単位のスクロールに対応させることが対応処理になります。

ということとは必然的に、「1回のスクロールでページが切り替わる」といった処理はこれに反します。

例えば、スクロールでページが1進むようなのがこれに該当します。

…厳しいですね。

「一定ピクセル数のスクロールになったらページを進ませる」というのも手ですが、引っ張り動作(スクロールさせた量だけ移動するが一定未満だと元の位置に戻る)を入れないと大変不親切なインターフェイスになってしまいます。

また、イージング処理イベントも飛んでくるので、引っ張り動作が正常に出来る保証もありません…。


というわけで、ピクセル単位のスムーズなスクロールを前提に作り直さないとどうにもならないなー、と個人的には思っています。

この方式は「見えている部分のリソースだけ処理して処理とメモリをコンパクトに」というのが大変やりにくいので、リッチな処理(重い)になる傾向が強いですし、全てを対応とかでなく、天秤にかけて取捨選択が現実ラインではないかと思います。

ページ切り替えぐらいで悩むならボタンでもいいかなってね。

かしこ

2014-07-27

タッチデバイス

何年ぶりかわからないですが、タッチデバイスについて調べる機会があったので記しておきたいと思います。

ログまでとってあるので、それなりに役立つはず・・・。

まず使う必要はあるのか?

マウスの代用であればそのままの状態である「レガシーモード」でも一応は事足ります。

が、タッチ操作においては「マウスダウン相当が無い」というのがマウスやペンと大きく異なる挙動の1つです。

これは主に「プレスアンドホールド」機能(押しっぱなしで右クリック)の弊害で、指を離すまでは左クリックか右クリックかを決定出来ないため、指で押してもマウスダウンが発生しません。(勿論回避方法はあるのでそれは後記)

もし、クリックだけで構成されたユーザインターフェイスであれば、そのままでもタッチデバイス対応のアプリであることを理解してください。

もし自前で実装したスクロールバーや特殊なGUI(ゲームライクなGUI)がある場合は、タッチデ操作を意識したプログラムを組む必要があるでしょう。

モード

windowsにおけるタッチデバイスは主に3種類のモードがあります。

  1. LegacyDevice(レガシーデバイス)
  2. TouchMDevice(タッチデバイス)
  3. GestureDevice(ジェスチャーデバイス)

レガシーはそのままの状態でOSがタッチ操作をマウス操作に置き換えてくれます。

タッチはタッチ操作の生データを貰う方法で、より反応の良い挙動が可能です。が、後記する制約により単純に反応が早くなるわけではなく、ズームジェスチャーなどにも対応しません。

ジェスチャーはパンやズームなど特殊な操作をOSで解析して使用出来るモードです。タッチといえばコレですが、ほぼタッチアプリ専用です。マウスと混同使用を考えると相当苦戦されるでしょう。

プレスアンドホールド

windowsではジェスチャの1つであるプレスアンドホールドだけが特別な機能として別枠でもうけられています。

ペン(デジタイザ)とタッチ共用設定で、OSの設定関係なくアプリケーション層でOn/Off切り替えが可能です。

設定はグローバルアトムにて行います。

const TABLET_DISABLE_PRESSANDHOLD=$00000001;

TabletAtom := 'MicrosoftTabletPenServiceProperty';
AtomID := GlobalFindAtom(TabletAtom);
if (AtomID=0)then AtomID := GlobalAddAtom(TabletAtom);
flg := GetProp(windowhandle,TabletAtom);
SetProp(windowhandle, TabletAtom,flg or TABLET_DISABLE_PRESSANDHOLD);

このプレスアンドホールドの有無によってタッチ操作時のイベントの内容が変わります。

なので、3モードx2プレスアンドホールド=6 のパターンが存在します。

マウスダウンとクリック

タッチ操作でもうひとつ考慮したい点がこのマウスダウンです。

マウスで左ボタンを押し込んだ時にボタンのグラフィックが変わる挙動を実現するには、このイベントが必要になります。

タッチ操作では基本マウスダウンが指を押したときに発生しません。

プレスアンドホールドの関係で指を離すまで左右のボタン判定が決定しないため、離すタイミングで一気に(クリック)イベントがなだれ込みます。

wait	//指を離すまでイベント無し
mouse(FromTouch).move...0(194,154) 7543ms
mouse(FromTouch).down...0(194,154)Left 11ms
mouse(FromTouch).up...0(194,154)Left 6ms
mouse(FromMouse).move...0(194,154) 7ms

これはペンやマウスとは全く異質なイベントの流れで、もしクリック処理を「GetAsyncKeyState」によってポーリングを行っている場合、マウスダウン間隔が短すぎてクリック処理がすり抜けます。

必ずイベントを見て補間なりしないと、クリックすらできないアプリが出来上がります。

と、ここまでが前置きです。

2011-05-12

CharaCombine(画像結合全パターン出力ツール)

ふと自動トリミングで良いアイデアが浮かんだので形にしようと、GWで仕上げる予定だったツールですがちょっと足が出てしまいました…。

f:id:Ko-Ta:20110512203344j:image

・CharaCombine ダウンロード

http://kota.dokkoisho.com/#CharaCombine


・概要

複数の画像をあれこれ合成して、全パターンを出力します。

つまり、立ち絵の切り出しなんかに使うと作業効率が良くなるんじゃないかな?と思われるツールです。

ポーズ8種、服装7種、持ち物4種、表情12種の場合は、8x7x4x12=2688ファイル出力します。

ただし、ポーズが大きく変わる(表情の位置など)場合は、プロジェクトを分けて管理しなければなりません。


このツールの特徴は自動トリミングで、中央位置を維持したり、顔の部分だけ抜き出すような任意指定もできたりします。

PSD読み込みは出来ないので、一度PNG出力する手間はありますが、それでも楽になると思います。

出力の際は、透明部分の色を塗りつぶして読み込みを軽くしたり、リニアフィルタ時の色漏れ処理も行います。


・使い方

ちょっと色々設定項目と機能があるので難しいかもしれませんので、付属マニュアルとにらめっこしてください。


・バッチ処理対応

コマンドプロンプトからカキカキすることで、自動的にはき出して出力するバッチ機能がついています。

複数のプロジェクトを一度に吐かせる際に役立つでしょう。


・対応フォーマット

読み込み:PNG(24bit/24+8bit),Bitmap(8/24/32),Jpeg

書き出し:PNG(24+8bit),Bitmap(32)


・バージョンアップ情報

2011/10/25...オーバーラップイメージ機能を修正

2011/05/19...小さい範囲を切り出す際に座標が狂うバグを修正。

2011/05/16...トリミング範囲設定に有効設定を追加。URL間違ってたのを修正。

2011/05/12...公開


PhtoShopのレイヤ結合計算式

さて、今回は画像の結合を行う必要があったので、普通のアルファブレンドではなく、Photoshopにおけるレイヤ結合の計算式を使用しました。

普通の合成と違ってMatrixのCompositeと似てるように思えます。

ゲームではほとんど、または全く使用されない類のものだと思います。


基本的には2枚の画像、src(上)、dest(下)を元に計算します。

何枚も重なる場合は、下から上に順に何回も行っていきます。

(たぶん上からでも大丈夫なんじゃないかな。そのほうが手前描画と同じ原理で最適化が利く事が多いかもしれません)

計算式はこんなかんじ。

src...上の画像
dest..下の画像
out...結合結果

da = (1.0 - src.a) * dest.a
out.a = src.a + dest.a

out.rgb = src.rgb * (src.a/out.a) + dest.rgb * (da/out.a)
  ↓
oa=1.0/out.a
out.rgb = src.rgb * (src.a*oa) + dest.rgb * (da*oa)

※例外
src.a==0.0...スキップ
src.a==1.0...dest.argb=src.argb
dest.a==0.0..dest.argb=src.argb

Alpha50%とAlpha50%を合成する場合、上の画像が50%、下の画像が0.5x0.5=25%の配分になるよー、ということ以外はアルファブレンドと似たような計算式です。

ただ50%と25%では100%にならないので、足した75%で割ることで、66.6%と33.3%に比率を調整する必要があり、割り算が発生します。

でも逆数(1.0/n)を一回求めておけば加算と乗算の式に置き換えることが出来るので、最適化する際は行列計算を上手く使えそうな気がします。

srcが100%と0%の時に最適化、destが0%の時に例外があるので、Shaderの時はちょっと考えないといけませんね。

上の式では「通常」合成に当たります。

ゲームでは割り算は御法度なため、alphaの計算にスクリーン*1を用いられることが常な用です。

*1:a1+a2)-(a1*a2