透明なウィンドウということで、このシリーズも第3回。今回が最後となりそうです。
ようやく Windows7,Windows8両方ともで動かせるやり方が発見できました。
なお、Windows7のAeroGlassOFF状態でも動くので、注意して実装すればWindowsXPでもこの方法でいけるのではないかと思います。
その方法は、レイヤードウィンドウを使う方法です。
これを使っての半透明ウィンドウはWindows7,Windows8ともに正常に動作することが手元では確認できました。
ただし、レイヤードウィンドウの簡単なサンプルによくあるSetLayeredWindowAttributes関数を使ってしまうと、ウィンドウ全体での半透明設定や、カラーキーによる抜き色指定になってしまうため、背景とうまく溶け込ませた半透明の処理があまりうまく出来ないため、使用しないでおきます。
半透明もうまく処理するレイヤードウィンドウの作り方としては、DIBとUpdateLayeredWindowとを使って実現します。
DIBで半透明用のメモリ上のフレームバッファを用意して、その中にデータを書き込み、その結果をUpdateLayeredWindow関数で転送して、画面に表示します。この部分はGDIに関係する処理となります。
この手順の中で、「その中にデータを書き込み」の部分ですが、レイヤードウィンドウの各ピクセルの条件において、乗算済みアルファであることを要求されるので、その点に注意しながら実装を行います。
さて、ピクセル列にまでなったデータを表示する方法はこれでわかりました。あとはこれをどう用意するかですが、これにはDirectXであれOpenGLであれ、一度書いたデータをメインメモリ上に読み直す、取得し直すことが必要になってきます。いくつかの方法はあるでしょうが、環境に合わせてパフォーマンスと相談しながら実装を検討することになるかと思います。手頃で簡単なものは、DirectXであればバックバッファをロックできるようにフラグを立ててしまうか、OpenGLならglReadPixelsの関数で読み出してしまうとか。
ただ、ラスタライズした結果を読み戻す処理になるのでそれなりに負荷がかかるのは仕方のないことでしょう。
(ただ、今はPCI-Express接続になっているし、昔のAGP接続に比べて転送がネックになることが少なくなってきている、との話もあるので実際に計測してみないことには何とも。)
結果
手元で実装したものの結果を貼っておきます。まずはWindows7で動かした物です。
背景にコードが若干見えると思いますが、これはOpenGLで実装しているものです。
一方で、これをWindows8で実行したものです。こちらはスマホのカメラで撮ったのでちょっと画質がイマイチです。
でも、どちらの場合でも描画した結果をデスクトップ上に半透明も有効にして重ねて描画できていることが確認できるかとおもいます。
追記
この透明ウィンドウ関連の話をされている、こちらhttp://umezawa.dyndns.info/wordpress/?p=3455 のページでもレイヤードウィンドウを使ってWindows8で期待通りに動いてくれる、とあります。 Windows8ではやはりこの方法できまり、という感じですかね。
コメント
would you please send me the code, which is about transparent opengl window
I need them so much !
thank you!
my mail is : lindawei520@163.com
Thank you for your comments.
I search for code on my hard disk, but I could not find it .
so, I will write advice as far as I can remember.
– use for ‘CreateWindowEx( WS_EX_LAYERED, …)’
– create Memory HDC (for offscreen DC)
– Drawing on OpenGL
– Get pixel data of the frame buffer using glReadPixels
– Copy from frame pixels to memory DC
– UpdateLayeredWindow with memory DC