ちゃんとは調べてないけど、どうもPNGの読み込みでつっかえてる。
exketはPNGの読み込みは単純に CImage::Load で済ませちゃってます。
libpngも試してみたんだけど、CImage::Loadの方が速かった。

で、Wineでは、CImage::LoadのPNG読み込みはlibpng使って実現してるんじゃないかな? みたいなかんじで、それに応じて読み込みが遅い。結構これが致命的。

あと、exketはページ画像読み込みとかのバックグランドスレッドは表の画面描画を邪魔しないためにスレッドの優先順位を低くしてるんだけど、Wineだと優先順位差によるCPU時間の配分がWinと違うっぽいなあ。まあ仕方なす。Wineは動けば万々歳とかそんなカンジで。
こんなカンジで動く。


基本的に、選択サークルをマップ上に図示する。
というかそれだけ。
あとは、対象サークル(一覧で表示してるサークル)のテーブルを淡く色付けしたり、その中で画面内に表示されてるサークルのテーブルをちょいと濃い目に表示してみたり。
画面上に表示されてるサークル群が、マップ上のどのあたりになるのかがひと目で判る。

マップ上のテーブルをクリックするとサークル表示部で該当サークルが選択されるとかの逆連動もできたら便利そうだなあ。





印刷用のレイアウト画面表示はタブで「レイアウトタブ」ってのを作って対応しようと思ったが、これだとサークル一覧表示とレイアウト表示を切り替えて見るしかない。
印刷用レイアウト画面は別ウィンドウに開いて、一覧表示の方からレイアウトウィンドウへサークルをドラッグドロップできるようにした方が便利そうだなあ。とか。

うーんどうすっぺ。
CImageは Load() 一発で PNGもJPEGも読んでくれるし、オフスクリーンでイメージを持つのにいろいろと便利。

というワケで exket でも CImage を多用してるんだけど、DebugビルドだとASSERTが出るようになった。場所は決まって atlimage.h の GetDC() か ReleaseDC() なんだけど、出るタイミングに全く再現性が無く暫く悩んだのだが、こういうことだった。


CImage は、生成されたオブジェクトひとつひとつが個別にデバイスコンテキストを持つワケじゃない。CImage::GetDC() すると HDC が作られて返されるが、CImage::ReleaseDC() してもその HDC は破棄されずにプールに蓄えられる。次回 CImage::GetDC() された時には、プールに HDC があったらそれが渡される、みたいな実装になってる。

このプールは CImage全体で共有されていて、
 CImage a;
 CImage b;

 HDC ahdc = a.GetDC();
 a.ReleaseDC();

 HDC bhdc = b.GetDC();
 b.ReleaseDC();

みたいなことをやると、a.ReleaseDC() でahdc がプールされ、b.GetDC() はそれが返ってくるので ahdc と bhdc は同じものだったりする。

当然ながら、

 CImage a;
 CImage b;

 HDC ahdc = a.GetDC();
 HDC bhdc = b.GetDC();

 a.ReleaseDC();
 b.ReleaseDC();

って場合は、ahdc と bhdc は違うものになる。


CImageを大量に作成した場合を考えると、デバイスコンテキストを CImageオブジェクト間で再利用するこの方法は理に適ってるとは思う。 exket も画面に表示する分のサークルカットを CImage で持ってるので多いと300個以上になる。が、300個が同時に描画操作をするワケじゃないのでデバイスコンテキストを300個持つのは不経済。この再利用式なら、多くても数個で済み、CreateCompatibleDC()呼ぶ回数も最低限に抑えられる。



だがしかーーーーーーし。

やっぱりマイクロソフトはマイクロソフトだった。


GetDC()/ReleaseDC() の動作がアトミックじゃなかったのですよ。
2つのスレッドが別々の CImageオブジェクトを操作していて、不幸にもほぼ同時に GetDC() してしまった場合、どちらのスレッドもプールから同じHDCを渡されてしまうことがある。
この時、ひとつのHDCに対して、2つのスレッドが同時に SelectObject() で各々のビットマップを対応付けようとしてしまう・・・・  ハイ。 予期せぬタイミングで楽しいことが起きますネっ。

クラスのスタティックなメンバ変数はクラスで囲われていても結局は大域的なのでマルチスレッドを考えて気を付けないといけないよー、というオハナシ。っていうか気をつけてね、マイクロソフトさん!!!!!!!


で、対応策だけど、CImageのラッパークラスを作って、GetDC() とReleaseDC() をクリティカルセクションで囲ったものを用意して使えばいいいじゃん。

と思ったんだけど、俺は甘チャンだった。

CImage のメンバ関数はかなりいい勢いで内部で GetDC()/ReleaseDC() を呼んでいる・・・
StretchBlt() とか。
それらも全部クリティカルセクションで囲うか?


もういっそ、atlimage.h を直接書き換えて、
GetDC() / ReleaseDC にクリティカルセクション追加しちゃうか?

っていうか CImage なんか使わないで代替クラス自分で作った方がよくね?


VC2008 とか VC2010 だと改善されてるとかそんなことは無いですよね・・・

うーん・・・・・   -_-;..