トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

独り言日記(2006/01)

独り言日記

続・Shade8でのOpenGL on dialog_interface(2006/01/27)

メモ書きです。OSXで、以下のVer0.02はOpenGLのウィンドウをCreateNewWindowで生成して管理してますが、HIViewのイメージから「HIViewGetWindow」を使ってWindowRefを取得してOpenGL領域を割り当てる、とするともっときれいにいけそうな気がしてきました。また、時間のあるときにバージョンアップしてみます。

参考資料へのリンクです。

http://developer.apple.com/documentation/Carbon/Reference/HIViewReference/HIViewReference.pdf

Shade8でのOpenGL on dialog_interface(2006/01/26)

dialog_interfaceでのOpenGL描画を更新しました。OSX版のソースとサンプルプラグインをアップしてます。かなり強引なやり方ですが、それを分かっていただければ幸いです(^_^;;。また、Windowsのほうも少し修正を加えましたので、Ver0.02として再度ソースの更新をかけるようにしてください(関数・引数は変わりはありません)。

解説書く前に力尽きましたので、詳しいことはまた後で。OSXでは、マウスイベントの取り方は強引です。先日の日記での追加事項ですが、モーダルダイアログの脇からマウス処理をGetするために、タイマーイベントでマウスを監視してそこからマウスイベントを作るようにしてます。

不可能を可能に(2006/01/25)

大それたタイトルですが(^_^;;。ほんと、これは不可能に近いことをしていたりします。

まず、Shade8(OSX)のダイアログ(dialog_interface)を細かくチェックしたのですが、

  • WindowRefが階層を作っているわけではなさげ
  • ControlRefでコントロールが配置されているわけではなさげ
  • HIViewで階層を作っているわけではなさげ(ルートのHIViewはあるのですが、、、)

で、じゃあdialog_interface上のwindow_interfaceではどのようにコントロールを配置してるんだ?というのは結局探れませんでした。ダイアログが1つのWindowRef(実際はNSWindow)を持つ、これを検出というところまでは、Cocoaからのチェックで分かりましたが。

ShadeというよりもMacOSX自身のダイアログのイベントループを奪うこと自体がかなり無理っぽいことのように感じてます。後は、Cocoaとの関係ですね。Cocoaで生成したウィンドウ(NSWindow)はCarbonからはFrontWindow/FindWindowでゲットできないという問題です。残念ながら、Cocoaからのアプローチでも上記3つ(ルート以下の子のウィンドウまたはコントロールを取得)は取れませんでした。これに加えて、マウス・キーボードのイベントを「モーダルダイアログでは」横取りできなかった、これも大きいです。(ダイアログのループは、すでにdialog_interfaceのがありますので、これに並列して独自のスレッドでまわしてちょっかい出してみたのですが 描画以外のイベントがゲットできませんでした)

しかし、上の画像ではこれを無理からに実現してます(OpenGLウィンドウの配置位置だけ、制限があります)。タイマーでティーポットが回転もしてます。マウス・キーボードの横取りもOKです。ダイアログの背景は灰色で変わってしまっているのは、Shadeのバグっぽいです。と、もう少しで、Winと同様にOpenGL on dialog_interfaceが完成しますので、また出来次第解説しますね。

・・・私からの提案として・・・・OSXで凝ったことをしようと思うなら、dialog_interfaceは止めて独自にWindowRefを「CreateNewWindow」して「RunAppModalLoopForWindow」でぶん回したほうがいい、とそう感じます。さんざん掘っておいてなんなんですが(^_^;;。

OSXでアプリを作ること自体は(資料が少ない、API自身にバグがあるというのを除いて)そう難しくはないのですが、イベント横取りはWindowsよりも厳しいですね。

あ、それとOSX 10.4.4で確認してますが、スレッド周りは初期の10.0や10.1時代と比べてかなり安定してます。変なこと(特にメモリリークと描画などのバッティング)をしない限りは落ちませんね。横取りが必要な場合は、これは例えばShade本体でOS依存のAPIにアクセスできる仕組みを実装してあげるほうがスマートである気もします。う〜ん、でもOSX版のShadeでは 本体CocoaでプラグインがCarbonなので、このあたりはOS自身(の橋渡し)がしっかりしないと難しいところではありますね。

・・・ところで、OSXではJavaもネイティブ実装でしたよね、どこまで使いものになるもんなのだろう・・・。

Objective-C++(2006/01/18)

OSXのCarbonからCocoaの機能を呼び出す場合、1つのソースファイル内にC言語(またはC++)とObjectiveCが混在することになります。このような言語体系を「ObjectiveC++」と呼ぶらしいです。

これ、ずっとつまずいていたのですがファイル拡張子が大事です。リンクするファイルがすべてC言語(*.c)の場合は、cocoa(ObjectiveC)の記載するファイルの拡張子は「m」でOKです。Appleのサンプルである「CocoaInCarbon」も、C言語+ObjectiveCの組み合わせ。このサンプル、Cocoa - Carbonの例として、かなり簡単に書いてありわかりやすかったです。

http://developer.apple.com/samplecode/CocoaInCarbon/CocoaInCarbon.html

ところが、1つでも他のソースファイル にてC++が混じっていると(*.cpp)、ObjectiveCのソースファイル拡張子を「mm」としないといけません。でないと、ビルドの最終段階のリンク時に「undefined symbols」が出たり、ビルドは通っても実行した後にCocoaを呼ぶC関数にアクセスすると落ちたり、と不安定になってしまいます。

いやはや、これを発見するまで1日費やしてしまいました。またOSかコンパイラのバグかと思ってしまいましたよ(汗)。

で、ついにやりました!!ヤマカンがあたったようです。OSX版のShade8はメインウィンドウとモーダルダイアログはCocoaで書かれており、上記のように「Carbon ==> Cocoa」の呼び出しでCocoaから管理しているウィンドウをたどることで目的のウィンドウ(モーダルダイアログ)をゲットできました。

つまり「Carbonで生成されたウィンドウはCarbonAPIのFrontWindowで取得できるけど、Cocoaで生成されたウィンドウは取得できない(同一プロセス内であっても)。この場合は、CocoaからNSWindowを取得してWindowRefに変換してCarbonに返してあげるとよい」の理論は正しかったことになります。

おかげさまで、MacでのShade/dialog_interface上のOpenGL描画は無事完成しそうです。数週間悩んだ甲斐があったというもの。

Cocoaでは、以下の要領でCarbonで言う「FrontWindow」による最前面ウィンドウがゲットできました。

NSArray *ar;
NSWindow *win;
int cou;
WindowRef winRef;
 
ar = [NSApp orderedWindows];             // 管理しているウィンドウの配列を取得
cou = [ar count];                        // 配列内のウィンドウ数を取得

win = [ar objectAtIndex:0];              // オブジェクトの取得(0番目のNSWindowを取得)
winRef =  (WindowRef)[win windowRef];    // NSWindowをWindowRefに変換

ちなみに、Shadeでモーダルダイアログを出してから上記のCocoaルーチンを呼ぶと、NSArrayの0番目はダイアログのウィンドウ、1番目は大元のメインウィンドウ(図形ウィンドウがある一番大きなドキュメントウィンドウ)が返ってきてました。フローティングウィンドウはゲットできてませんでした。ということは逆もしかりで、「Carbonで生成したウィンドウは、Cocoaからは検出できない」ってことなのかな。

OSXの場合は、Carbon/Cocoa両方使えないと他のアプリを乗っ取ったりというのは完全にはいかない感じですね。

追記(2006/01/17)

OSXプログラムにて追記です。「/アプリケーション/ユーティリティ/アクティビティモニタ」でプロセス一覧からスレッド詳細までもっと分かりやすく見ることができました。後、ShadeプラグインからモーダルダイアログのWindowRefが検出できない問題に加えてもう1つやっかいなことが。

CarbonAPIのCopyWindowTitleAsCFString(旧GetWTitle)で、WindowRefのウィンドウタイトルが取得できるのですが、これがWindowRefがゲットできているShadeフローティングウィンドウの場合でも取得できてません(Shadeプラグインでの話です。独自のCarbonだけのアプリでは問題なく取得できてます)。

で、いろいろ調べてみた結果、SDLでも同様な現象が起こるようで(OSX版のSDLはCocoaでコーディングされてます)、「CarbonからCocoaのNSWindowの情報がうまいこと取れない」が現実味を帯びてきた予感。どちらかというと、OS自身の問題でしょうかねぇ。ここまで、原因を時間をかけて絞り込んできたわけですが、最後の切り札として「Cocoaでフロントウィンドウを取得してCarbonに渡す」が残りました。

ということで、Cocoaの勉強もするかぁ。幸い、OSXではCocoa/Carbonの情報交換は1つの実行ファイル(プラグイン)でも混在して行うことができます。ツギハギゆえの不都合ですが、ツギハギゆえに助かるかもしれない、といったところ。

さらっと見た感じでは、Cocoaのほうがソースが短くてすみそうですね。しかし、構文が独特なのでまずは理解から始めないと。

・・・文章を見返してみましたが、Carbon/Cocoa/NSWindow/WindowRef/SDLとか・・・知らない人から見ると暗号ですな(^_^;;。

OS XのNSWindow/WindowRef(2006/01/17)

OSXでのShadeの挙動を深く探ってみます。プロセス名は「xshade」、初期状態のスレッドは6つです。Shade自身のスレッドを監視したところ、根本は「NSApplicationMain」から始まっており、Cocoaで作られていることがわかります。

モーダルダイアログ(dialog_interface)のウィンドウハンドル(WindowRef)が「FrontWindow/FrontNonFloatingWindow」で取得できないので、一週間以上いろいろと調査しているのですが、モーダルダイアログ自身はCocoaのNSWindowから生成しているのではないかと推測してます。

テスト的に作ったアプリでは、モーダルダイアログのWindowRefも外部スレッドから検出できるんですよね。しかし、Shadeのモーダルダイアログは検出できず。また、メインウィンドウも検出できません(フローティングウィンドウは検出できます)。Cocoaはプログラム方法が分からないのでタッチできないのですが、たしか昔のShade(Shade6くらい)では、メインウィンドウ・ダイアログ共にWindowRefが検出できていた記憶があります。

で、Shadeはモーダルダイアログを表示するときに1つスレッドを生成するようです。これは1度生成したらShadeを終了させるまで保持するみたい。また、メインスレッドでは「-[NSApplication runModalForWindow:]」でモーダルのイベントループをCocoaで発生させてます。

総合的な検証では、「Cocoaで生成したウィンドウ(NSWindow)は、CarbonのFrontWindow/FrontNonFloatingWindowで取得できないのではないか」という疑惑が。う〜む、NSWindowあたりを取得するAPIがCarbonにないものか・・・。

この上記のような調査は、当然Shadeの中の人でないとソースは入手できないため探ることができないと思ってしまわれがちです。ただ、いわゆるWindowsで言うSpyツールのような感じで、スレッドの挙動を監視することは実は可能です(ウィンドウの階層を見るのがないかなぁ)。

OS Xに開発ツールをインストールしたときにできるDeveloperフォルダ内の「Applications/Perfomance Tools/Thread Viewer」を起動します。これでプロセス(起動しているアプリ)を選択するウィンドウが出るので、対象プロセスを選択します。これで、スレッドごとの情報が表示されます。

・・・window_interface/dialog_interfaceで使うネイティブなWindowRef(Windowsの場合はHWND)を返してくれる関数を1つ追加してもらうと万事解決すると思うのですが(^_^;;。回りくどいです(苦笑)。OpenGL on ダイアログまでの道は険しそうですね。

WindowRefの階層化(2006/01/12)

OSXでウィンドウを作る場合はCreateNewWindowを使うのですが、この引数には親ウィンドウの指定がありません。ウィンドウの上にウィンドウ描画領域を設けたいのですが・・・。で、さんざん探して見つけました、「SetWindowGroup」でどうやら階層化できるようです。しかし・・・分かりにくい・・・・。

WindowGroupRef gr;
...
CreateWindowGroup(kWindowGroupAttrMoveTogether |
    kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse,
    &gr);
SetWindowGroup(win1, gr);      // 親のグループを登録
SetWindowGroup(win2, gr);      // 子のグループを登録

のようにすると、WindowRefであらわされるウィンドウwin1にwin2が関連付けられます。win1のウィンドウを動かすとwin2はそれについてきて、無事ウィンドウにウィンドウを割り当てる、ということができます。win2表示時に下に影ができるのですが、これはCreateNewWindowの第二引数でkWindowNoShadowAttributeを指定することにより影ナシにできます。

これ、何をしているのかというと、ShadeのダイアログでOpenGL描画を行う実装です。この場合、ダイアログのウィンドウの上にOpenGL用のウィンドウを乗っける必要があります。しかし、まだまだ壁があって、Shadeのモーダルダイアログはなぜかウィンドウハンドル(WindowRef)をゲットできない。う〜ん、フローティングウィンドウではゲットできるんだけどなぁ・・・。

Qcam(2006/01/09)

急に思い立って実験してみたいことがあったので、Logitechの「Qcam for Notebooks Deluxe」というUSBカメラを買ってきました。

http://www.logitech.com/index.cfm/products/details/JP/JA,CRID=2204,CONTENTID=10168

ソフマップでポイント使って2000円代、安い買い物です。

プログラマとしては付属ツールなんてただのパセリ、プログラムでいじれないと意味がないということで制御できるか調査。Windowsでは、DirectShowにてカメラのキャプチャ関連は制御できます。現在、DirectShowはPlatformSDKに移行しちゃってるんですね。必死でDirectX9SDKからinclude/libを探してました(^_^;;。

DirectShowの機能を使うと、1フレームごとの画像をRGBでゲットできます。これができるといろいろ研究に使えそうです。たとえば、動いている物体のみを除去したり、動きをモーションキャプチャしたり、ASIMO風視覚センサーを作ったり・・・。

手始めの実験として、セピア調フィルタをかけてみました(プログラムで制御してます)。上半分は普通の色、下半分はセピア変換してます。

リアルタイムにかけることができるので、昭和風な雰囲気をカメラ動かしながら出せて楽しいです。いまやUSBカメラは安価で手に入りますし、最大120万画素まで表現することもできるようになりました。大学や余裕のある企業などで、この手の研究が流行ると面白いなぁと思うのですが、いかがでしょうか。

MacでのOpenGL(2006/01/07)

CarbonでOpenGL描画を扱うアプリ(ツール)を作るのはすごく簡単です。ここに実験ソースを置いておきます(Shadeとは関係ないよ)。「AGL」というのを使うとOpenGL描画領域をアタッチできます。後は、glXXXのおなじみのOpenGL APIを並べるだけ。また、GLUTもOS XではOSに内包されてますので、これもすぐに使えます。

で、Shadeで処理を奪う(独自OpenGL描画領域を実現する)には、、、それ以前の問題で対象の親のWindowRefをゲットするのが難問です。WindowRefの親子関係を取得するAPIはCarbonにないものかな・・・。Cocoaではあるみたいですが。

Shade8 プラグインSDK - dialog_interfaceのOpenGL(2006/01/05)

dialog_interfaceでのOpenGL描画を行うソース一式をアップしました。リンクよりソースとサンプルソース・サンプルプラグイン(DLL)をダウンロードできます。一応アルファ版ということで。

解説はまだ・Mac対応もまだですが、sample01.cpp 〜 sample04.cppを見ると、なんとなく使い方は分かるかなと思いたいです(^_^;;。解説は後で細かくいれます。ちなみにサンプルソースであるsample01.cpp 〜 sample04.cppは、Macでも実装は変わらないように設計しています(そのままMacに持っていけばコンパイルがとおる予定)。「opengl_window_class」というOpenGL描画を扱うクラスを新設してプラグインSDKを拡張しています。

opengl_window_class関連のファイル(dialogopengl.cpp/openglwindowinterface.cpp/oglKeyboard.cpp/oglMouse.cpp)は見なくても問題なしです。が、これを実装するために水面下でえらいことをしないといけない、というのが理解されればしめたもの(苦笑)。Shade上のモーダルダイアログでまともにOpenGLを使おうと思うと、こんだけの処理・苦労をしないといけません。

私はオーバーライドの仕様はあまり好きではないのですが、ShadeプラグインSDKにあわせるためにあえてこんな実装にしてます(私はコールバック関数をアタッチするほうが好きなもんで)。ドラッグ処理はこっち(opengl_window_class)のほうが分かりやすいかなと思ってますが、どうでしょうか。

それと、仕様はもうこれで固まってますので自作プラグインに実装されてもOKです。残すはMacへの移植とAPIの説明を書きますね。

しかし、dialog_interfaceの上にwindow_interfaceをマッピングする、これ自体が付け刃的でかつ複雑かなぁという気がします。これもラップはできるのですが・・・面倒なのでパスします(^_^;;。

Shade8 プラグインSDK - window_interfaceのkey_down(2006/01/05)

予想通りというか、ダイアログ内に配置するwindowinterfaceでの「window_interface::key_down」は呼ばれてませんねぇ。Windowsではキーボードフックすることで対応できるのですが、Macではできるだろうか・・・。

Win版でのdialog_interfaceのOpenGL描画は実装完了。先にこっちのソースとサンプルを公開することにします(もうちょっとお待ちを、解説やソースダウンロードはTipsのページの方に移行します)。

しかし、Shadeを使っていると図形ウィンドウやフローティングウィンドウ上のちらつきが目につきます。原因は何なのだろう・・・、これが重い現象に関連しているような気配もしますが・・。

e-ラーニング(2006/01/05)

東京帰ってきました。親にパソコンの使い方を教えていたのですが、一日かけて使い方教えたところ 早速いろいろネットで検索してプリントアウトしてました。実家も私と同じso-netなのですが、マニュアルもより初心者向けで簡単になっていますね。

ただ、正直なところso-net提供の初心者向けのマニュアルや簡単設定のCDはまったく使いませんでした。ほんとにキーボードに初めて触る、という人から見るとまだまだ使える側(教える側)が意識を変えないといけないなぁと痛感しました。

まず、マニュアルといえども10ページ以上ほどあると読む気をなくしてしまいます(どんな簡単なことが書いてあっても)。2ページくらいにまとめたクイックリファレンスがあればいいかなと(これは、パソコンの電源を入れるところからネットにつなぐまで)。で、初心者さんのやりたいことは(おそらく)「ネットでの検索を使ったインターネット体験」「メールでのやりとり」が先に来るかと思います。というよりも、何ができるかからの模索、といったところでしょうか。これにしぼると、各2ページもあればそれぞれを解説できるんでないかなぁ。後、私も注意しなければならないのですが「うんちく」的なわき道にそれた解説は、これは注意をそらすかもしれない、と感じます。目標まで簡潔に一直線に説明するのが分かりやすい方法論かも。

後、難儀していたのが「ローマ字による全角漢字入力」。親曰く、タイプライターとは違うね、ってことなので(私が逆にタイプライターを知らない(^_^;;)団塊世代以上の方には関門の1つかもしれません。

それと、マニュアルでは無理だと思いますが動画でキーボード操作・ネット接続の操作を見せる、これも大事かも。パソコン上でとなると(たとえばFlashで)、そこにたどり着くまでが大変なので、紙の上で動画を見せることができるなんてあると一番ベストかな(ビデオだと、今度はデッキの使い方説明がいるもんで、やはり距離ができてしまう)。がんばれ、技術革新(笑)。

年寄りだからITにはついてこれない、ってわけじゃなく教え方の問題もいろいろあるんでないかなぁ、というのが私の感想です。

親の友人(もう軽く60歳超えてる)の方々は、普通にネット検索もメールも使いこなしているそうな。時代ですねぇ。

あけましておめでとうございます(2006/01/02)

今年もよろしくお願いいたします。今年の目標はまだ立ててないのですが、何か形に残すことができればいいなぁと。とりあえずはMayaを使いこなせるようになりたい、とアプリケーション(ツール)を完成させたいですね。仕事のほうは早く基盤(環境)づくりを安定させることができるように。

元旦に初詣に行ってきました。運動がてら計15駅分くらい歩きました(^_^;;。伏見から京都駅近辺+大阪御堂筋梅田からあびこまで。さすがに筋肉痛キました。同じく一緒に行った友人も筋肉痛ということで元旦からやりすぎ感がありますが、今年も気合入れていこうと思います。

Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.