フルスクリーンの簡単なお絵かきアプリを作るメモ
動画を制作するのに
- フルスクリーンで描ける
- UIがデフォルトでは表示されず、描画エリアを邪魔しない
- 背景ビットマップが別レイヤで読み込まれ、ペンタブで描いたストロークで上書きされない
ものを探していたところ、fulldrawを見つけたのだが、少し要件に合わなかった。
ソースコードを改造しようかなと思ったが、APIベースのソースなので画像読み込みとか面倒そうだった。
OpenSiv3Dにペイントアプリの簡単なサンプルがあったのでこれをベースに作ることにした。
でとりあえず作ったものの解説動画がこれ。
まだ機能は足りていないが、ペンタブを使って絵は描けるようになった。
ペンはWindows APIではマウスイベントとして検知されるようだ。が、筆圧・ペンの傾きなどの情報はマウスイベントだけでは取得できない。
fulldrawのソースを見ると、WM_POINTERDOWNメッセージでペンの筆圧情報が取得できることが分かった。
でこのイベントを捕まえるために、自前ウィンドウプロシージャを挟んでペンのイベントを捕まえてたが、どうもOpenSiv3D側でペンタブは対応してくれてそうなことをさっき知った。
やっぱりサポートしていた。
書き換えないといかんな。
こんな感じのコードになった。
if (!menuOpen) {
if (MouseL.down()) {
Stroke s{};
s.color = penColor;
s.thickness = thickness;
PointData start;
start.pressure = Pentablet::IsAvailable() ? Pentablet::Pressure() : 1.0f;
start.pos = Cursor::Pos();
s.strokePoints.push_back(start);
s.drawing = true;
strokes.push_back(s);
currentStroke = strokes.end() - 1;
}
else if (MouseL.pressed()) {
PointData start;
start.pressure = Pentablet::IsAvailable() ? Pentablet::Pressure() : 1.0f;
start.pos = Cursor::Pos();
currentStroke->strokePoints.push_back(start);
}
else if (MouseL.up()) {
currentStroke->drawing = false;
}
}
しかしちょっとWindowメッセージを直接ハンドルしたものと比べると描画がガタガタするな・・
OpenSiv3Dのイベントループ単位の処理だと、座標データの取りこぼしがあるのかもな。気のせいかもだけど。
OpenSiv3Dでのペンタブのハンドルはwintab を使ってるのか。私はfulldrawのソースコードを参考にして、WM_POINTER_XXXをハンドルしていた。
OpenSiv3Dのソースコードをざっと見る限り、イベントループのタイミングでペンのステータスをpeekしてるような。
ウインドウメッセージだと、OSがキューイングしてくれるので取りこぼしはなさそうだけどね。wintabもその辺考慮はもちろんしてるだろうけど、このAPI知らんからよくわかんないな。
ちょっとAPIドキュメント読んでみるかな。
WT_PACKETというメッセージがあるんだな。
さらにAPI側が持つバッファを読み取らんといかんのだな。
こんな感じで、OpenSiv3DのPentabで書くとちょっとガタってなるんだよね。
太さはちょっと別にしても、滑らかさが違う。
OpenSiv3Dでのペンタブのupdate()見ると、やっぱりメッセージループ単位でデータを更新し、その間に得られたデータのうち最新のものをサンプルしてるようだ。
つまり描画フレーム間に動いた軌跡データが欠落するってことのようなんだな。
これが滑らかさの違いになって表れているように思いますな。
しかしこれはこういう仕様だと割り切っている感じもしますな。
しかしこのwintabっていうAPIだと筆圧の精度も上げられそうですな。
私が使っているのはかなり安物のペンタブなんだけど、それでも筆圧は8192段階検知できるのですわ。
WM_POINTER_XXX+アルファで得られる筆圧データの精度は1024段階なのでね。
ここまで作成したコマンドをアンドゥ・リドゥできるようにした。
また、ストローク単位でアンドゥ・リドゥができるようにしてみた。