2009年12月27日日曜日

フルパスからフォルダ名を取得

 文字列操作とか面倒だなー、何か適当な関数ないかなーと探し回った。

 ざっくりいえばファイルパスをPathRemoveFileSpec()でフォルダパスにして、 PathFindFileName()でフォルダ名だけ取り出せばいける。
これらの関数を使うのに「shlwapi.h」と「shlwapi.lib」のリンクが必要。



以下実験
#include <cstdio>
#include <tchar.h>
#include <windows.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
 
int main()
{
  TCHAR path[ MAX_PATH ] = {0};
  GetModuleFileName( NULL, path, sizeof(path) );
  _tprintf( TEXT("%s\n"), path ); 
 
  PathRemoveFileSpec( path );
  _tprintf( TEXT("dir: %s\n"), path ); 
  
  _tprintf( TEXT("dirName: %s\n"), PathFindFileName(path) );
 
  return 0;
}

実行結果


D:\develop\study\test_cv2012\Debug\test.exe
dir: D:\develop\study\test_cv2012\Debug
dirName: Debug
続行するには何かキーを押してください . . .


 といった具合。
GetModuleFileNameで自分の実行ファイルパスを取得。
PathRemoveFileSpec()でパスの一番後ろにある「\」以降の文字をバッサリカットしてフォルダパスに。
PathFindFileName()で一番後ろの「\」以降の文字のみを取得でき、これがフォルダ名となる。
 PathRemoveFileSpec()に渡せるパスがファイルかフォルダか不明瞭な場合はPathIsDirectory()でフォルダかどうか確認するのが手っ取り早い。
またフォルダパスの後ろに「\」がついていたりいなかったりする場合が考えられるなら、PathRemoveBackslash()で後ろの「\」をなくせるので利用したい。



以下私事。
PathCombineは"..\\filename.ext"と一個上のフォルダを指定してもちゃんとパスを修正してくれるが、"../filename.ext"とするとうまく動かない。\でないといけないみたい。

 起動時にGetCurrentDirectoryでフォルダパスを保存しておいて、
終了時にそのフォルダパス+ファイル名としてデータを保存していたのだけど、これが大失敗。
 ファイル選択ウィンドウなどでカレントを移動したあと
ShellExecute( NULL, TEXT("open"), execPath, NULL, NULL, SW_SHOWDEFAULT );
などと新しくexecファイルを実行すると、そのexecファイルのカレントフォルダも自身のパスにかかわらず、起動する側のカレントフォルダが反映される。
そのため終了時にデータ保存すると実行ファイルのフォルダとは別の場所に保存される問題が発生した。
 自分のフルパスからフォルダパスを得て、そこにファイル名をくっつけることでこの問題を回避した。
いけてないランチャからプログラムを呼び出された場合似たようなことが起こるかもしれないので、対策しておくといいも知れない。

[参考]
フルパスからフォルダを階層分割するには?
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200810/08100010.txt



2013-05-23:
 記事を書き直しました。
フォルダ名とフォルダパスをはき違えていた内容だったので。



2009年12月19日土曜日

日記ちゃんが大人の科学

Vol.26 ミニエレキ | 大人の科学マガジン | 大人の科学.net
http://otonanokagaku.net/magazine/vol26/index.html

 わずか3500円ぐらいでギター的なものが手に入っちゃう。なんちゃってピックも付いてる!
製作時間は約2時間程度。作り方説明がガンプラ並みに丁寧なので詰まることはないと思う。
必要なのは単3電池2本、+ドライバー、セロテープぐらい。
コイル巻くなんて何十年ぶりよ、小学生のとき以来で懐かし。
作ったにもかかわらずエレキギターが何で音が鳴るのかさっぱり分からない、これなんで音出るの?
 
 それはそうと弾くとか弾かないとか以前にチューニングが難しい。
弦のはじき方で地味に音が変わってあわせられないよ!
適当に近い音にしてCコード弾いてみたが、指が引っかかって音が出ないという。
友人がじゃんじゃんバリバリ弾いてたが、信じられんねこれ、難しい!
押せばチャラチャラポンポォンって音が出るピアノとは大違い。爪が長いと弾けないもの!
 
 近所の本屋には山積みされてたから、手に入りやすいと思う。
暇つぶしに買ってみるのはどうだろうか。

2009年12月14日月曜日

日記ちゃん半透明合成


for (BYTE i=0; i<256; ++i)
{
}


とかやっちゃってたぜ。ふへへ。死ぬがよい。

BYTEはWinDef.hで
typedef unsigned char BYTE;
です。



 半透明合成を実装する必要が出てきたので昔作ったやつを流用。とっても遅いのでどうにかしたい。


DWORD alpha = src >> 24;
DWORD colorRB = ((dest&0xFF00FF)*(256-alpha) + (src&0xFF00FF)*alpha) & 0xFF00FF00;
DWORD colorG = ((dest&0xFF00)*(256-alpha) + (src&0xFF00)*alpha) & 0xFF0000;
dest = ((colorRB | colorG) >> 8) | (dest & 0xFF000000);


 1ピクセル32bit限定でAABBGGRRとデータ並んでいる、普通のDIBデータ。
見てのとおり赤と緑を一度に計算、その後緑を計算し、くっつけて256で割るということを行っている。
各色を別個に計算するよりは速いが、高速化というと微妙なところ。
あと割り算をビットシフトにしてるが普通に「/256」と書いてもコンパイラの最適化がいいようにしてくれると思う。
 アルファ値は下地のままにする。
というか50%の下地に50%を上から合成したらアルファはなんぼになるべきなのか良く分からなかったので。25%? 50%? うーん。
下地100%に上から50%半透明合成をすると、結果100%のままなほうが自然か。
 これでも1024*768を80msぐらいでレンダリングできるのでまったく使えないわけでもない。
dest=srcなべた塗りだと20msぐらいの環境で。

 ちなみに普通の半透明合成の式は
color = (dest*(256-alpha) + src*alpha ) / 256
を各色。



●おまけ


dest = (dest & src) + (((dest ^ src) & 0xfefefefe) >> 1);


 50%限定半透明合成。

他にも、


DWORD color = (dest & 0x00fefefe) + (src & 0x00fefefe);
DWORD mask = color & 0x01010100;
dest = color | (mask - (mask >> 8));


 加算合成。


DWORD mask = ((( ( ((~dest & src)<<1) + ((~dest ^ src) & 0xfefefe) ) & 0x1010100 )>> 8 ) + 0x7f7f7f) ^ 0x7f7f7f;
dest = (dest | mask) - (src | mask);


 減算合成。

 昔どこだかで拾って使っていたもの。
特に加算合成には大変お世話になりました。
とりあえず、自分が考えたわけではないということを明記しなければならない。
それならブログに乗っけるなという話であるが、意外に合成式関係はググっても出てこないので。
誰かのお役に立てば幸い。
 最初の半透明合成だけは自力、ビットも糞もないのが笑える。

2009年12月11日金曜日

ふたご座流星群

ふたご座流星群の観察Q&A:国立天文台
http://naojcamp.nao.ac.jp/phenomena/20091211/observe.html

 13日:夜中から明け方
 14日:22時から3時頃まで
見る方向は気にしなくて良い。
また16日は新月で、月明かりに邪魔されずに観測できる。

とのこと。しし座のときですらかなり寒かったから、防寒対策はしっかり行いたい。

/** 15日 0:37 追記 */
いってくるぜー。

/** 0:45 追記 */
めちゃめちゃ曇ってた!

2009年12月5日土曜日

ステータスバーとアイコン


 ステータスバーにアイコンを表示するときは

SendMessage( hStatusWnd, SB_SETICON, 0, reinterpret_cast<LPARAM>(hIcon) );

などとすればいいが、アイコンの読み込み方によって表示のされ方に違いが出るようだ。上の画像はLoadImage関数で読み込んだもの。LoadIcon関数で読み込むと下の画像のようになる。要注意。




 ステータスバーに区切りを付けたいとき、


int iRight[] = { 100, 200, 380, 450 };
SendMessage( hStatusWnd, SB_SETPARTS, sizeof(iRight)/sizeof(*iRight), reinterpret_cast<LPARAM>(iRight) );


のようにする。このとき自分がはまったのが、指定する数値はてっきり横幅だとばかり思っていて

int iRight[] = { 100, 100, 100, 100 };

とかやって、おっかしいなあ、ぜんぜん区切られないけどなんなのこれ? と歯をギリギリしてた。正しくは位置を設定する。要注意。



 使用するアイコンをすべてリソースに追加したところ、実行ファイル.exeのアイコンが意図しないものになった。実行ファイルに設定されるアイコンはIDが一番若いものになるので、#defineなどで数値に置換し、実行ファイルに設定したいアイコンが一番若いIDになるよう修正する。要注意。プログラム中でアイコンを読み込む時は
LoadIcon( hInstance, TEXT("ICON_RESOURCE_NAME") );
から
LoadIcon( hInstance, MAKEINTRESOURCE(ICON_RESOURCE_NAME) );
といった具合に変更する。