カレンダー

06 | 2017/07 | 08
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -

カテゴリー

プロフィール

drednote(Mr.Ty)

Author:drednote(Mr.Ty)
既にいい年しているにも関わらずエロゲをプレイしているヤバイおっさんです。きっと還暦になってもプレイしてそうな気がする。

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

ブロとも申請フォーム

この人とブロともになる

主にエロゲのプレイ日記。他レビューっぽい事とか色々
エロゲプレイ記
  当サイト内記事にはゲームのネタバレが含まれる場合があります。
  ネタバレをみたくない方は、当サイトの閲覧をご遠慮願いますようお願い致します。
  また、当サイトの記事自体は全年齢対象ですが、
  扱っている評価物は基本的に18歳未満プレイ禁止の物が殆どですのでご注意願います。
[------]
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--------(--) --:-- スポンサー広告 | 編集 |
[20100508]
あまり深く設計しないでMVCっぽくプログラムを組んでいくと、どんどんConcreteObserverとConcreteSubjectが増えていく。
実際のところ、Observerパターンは適切に使いさえすれば非常に便利なパターンなのは間違いないんだけど、闇雲に使っちゃうとObserverの呼び出しが更にObserverを呼び出して、なんていう連鎖が発生しかねない。
こういう連鎖が発生しちゃうと最悪の場合、メッセージがループしてそこで延々ぐるぐるまわっちゃう事もありえるので気をつけないといけないんだけど、でもやっぱり便利なので使っちゃうわけだw
実際問題として、Observerパターンを使うと、その時点でConcreteObserverはSubjectに対して依存が発生してしまうので、闇雲に使っちゃうとクラスの独立性に支障をきたすんであんまよくない気がするんだ。
だから、モデルクラス同士で通信したい、と思ってObserver組んじゃうのは良くない。
やっぱそういうのはコントローラーに任せないと不味いんじゃないかな、と思った。
まぁ、そう思いながらもついつい使っちゃうんだけどね……
スポンサーサイト
[20100504]
Windowsで時間計測を行う場合、QueryPerformanceCounterを使用すれば比較的容易にマイクロ秒単位での実時間計測が出来る為、今まで使用してきた人も比較的多いのではないかと思う。
(それ以外のAPIは全てミリ秒単位の計測になるため、特に音楽系での用途には若干精度が不足する場面もあった為、好んでQueryPerformanceCounterを使用していた人も多いと思う)
で、このQueryPerformanceCounterの代わりに使用できるAPIとして.NETで用意されているのがSystem.Diagnostics.Stopwatchクラスなわけだ。
このクラスは実のところ殆どQueryPerformanceCounterそっくりに出来ており、おそらく.NETを使用してマイクロ秒単位の時間計測を行いたい場合はこのクラスを使用する事がほぼ決定事項になるのではないかと思う。
で、このクラスの実装方法なんだけど、もしこのクラスが内部でQueryPerformanceCounterとQueryPerformanceFrequencyを使用していた場合には問題になる。
QueryPerformanceCounterについての問題を実験されたサイトがこちら
QueryPerformanceCounterの内部実装がどうなっているのかはわからないのだが、実験結果から不正確な時間が帰る場合があるということがわかっている以上、そのまま無闇に使用してはならないという事になると思う。
(個人的には、そもそもSleep(1000)で正確に1秒きっかり停止しているかどうかから検証すべきな気もしてますが)
今までも、そもそもQueryPerformanceCounterが使用出来ないハードかどうかを調べるために、戻り値が0かどうかをチェックするようなコードは組んでいたと思うのだが、もうそれだけでは足りないという事になりそうだ。
そしてユーザープログラムがQueryPerformanceCounterを直接呼んでいる場合は値がおかしいかどうかを判定して使用するかどうかを判断すれば良いのだが、Stopwatchクラスの場合はその判断をクラス内部で行ってしまっている為、もしここでQueryPerformanceCounterを呼ぶ方法で実装されており、且つ戻り値が0の時には使用出来ない(=DateTimeを使用する)と判定しているのであれば、ユーザープログラム側で更にStopwatchの計測時間が本当に正しいのかどうかを改めて判定させる必要があるという事になるのではないかと思う。
Stopwatchクラスの場合、今までユーザープログラム側で行っていた使用出来るか出来ないか判定をクラス内部で行っている、=Stopwatchクラスの返す値を常に信頼してプログラムを書いている、という人も居るのではないだろうか?
そういう人の場合、少なくない変更が必要になる可能性があるという事を上の実験は示していると思う。
(まぁ、そもそもStopwatchクラスが正しくない値をかえすかどうかの実験やってないんで、なんとも言えないんですけどねw)
[20100421]
アクセサー、つまりget~とかset~とかのあれですな。
時々、アクセサー作る意味がわからん、とかこんなん作ってもしゃーないやん、という意見を目にするんだけど案外そうでもないよ、という話。

無論、大前提としてある程度考えたデータ設計にしてあるというのは必要なんだけど、アクセサーを置いておくのはそれだけで(非常に薄いけれど)抽象化と言えなくもないと思う。
つまり、そのデータ構造のそのプロパティ、という物を「そのデータ構造からそのプロパティがデータとしては無くなったとしても」そのまま保持し続ける、という意味で抽象化と言えなくもないと思うんだ。
これは、データにインターフェイスを被せることによって実装としてはもっと効率的な実装を求めながらもデータとしては理解しやすいデータのままの外見を保てる、とも言える。
まぁ、ぶっちゃけ現場的な話をすると、いきなり仕様が変わっちゃってデータ構造にもっと複雑な多様性を持たせる必要が出てきた時でもこうやっとけばわりと対応しやすい、という事になるんだな。
たとえば、なんらかの座標値を今までは整数型で持っていました。
でも、突然今までの整数型の値を16倍した値にして扱わなければならなくなったとする。
(本当はこういう突然の事態こそなくさなきゃならないんだけどね)
そんな時でもアクセサーかましときゃ、その中で16倍してやればそれで終わる。
16倍した値を格納される可能性があるなら、16倍した値用の新しいアクセサーを用意して、そっちは実際には1/16してから格納するか、或いは別の(新しい)データ領域に格納させて古いデータと新しいデータをgetのアクセサーでシームレスに扱わせるか、などやりようがある。
まぁ、美しくないと言われればそれまでではあるんだけど、でもこれネイティブにデータ弄ってたらどうしようも無くなってた、という場面をどうにか出来る可能性があるってのは結構大きいと思うんだ。
という事で、主に現場的な意味でアクセサーって良いよ、という話でした。
[20091002]
さて、えらく時間があいてしまいました。
言い訳をすると、仕事が単純に忙しかったんですw
更に言うなら、その後私が実装したよりももっと単純でもっと良い方法が(ぐぐったら)わかったというのもあります。

とりあえず回転の話の続きです。
前回で頂点座標は回転させましたが、そこからどうやって描画するかをやっていません。
描画する為にはドット単位の座標に変換する必要があるんですが、とりあえずその為に描画域を求める必要があります。
私が実装した時は、前提条件として
  1. 矩形を描画する(必ず4頂点であり、且つ平行四辺形等のように歪んでいない)
  2. 回転拡大縮小フリップはしている可能性がある
という条件がありましたので、その条件で考えた物です。
その条件でスキャンラインを求めるとすると、
 1.頂点から上限/下限を求めてY座標の最大/最小を求める
 2.Y座標について1ラインずつ見て行き、そのラインにおけるXの範囲を求める

の2段階に分かれると思います。
実際にはこの前に矩形の4つの角度チェックとか入れたほうが安全なんですが、とりあえず省いてます。
四角のままで回転させる場合は、矩形を前提とした方が楽ですし、そういった前提が出来る場合があります。
矩形を前提に出来ない場合は素直に三角分割した方が良いでしょう。
下記は矩形を前提とした方法で記述します。
で、上記の内少しだけ問題になるのは多分2番なわけですが、これは線の公式を使えば簡単に求まります。
y=(y2-y1)/(x2-x1)*(x-x1)+y1
上記の式を適当に変形させて使ってください。
で、描画域が求まったら後はその描画域の範囲内についてforループをまわし、その座標が元画像ではどの座標に相当するのかを求め、その座標の色を描画します。
一番問題になるのがこの、回転結果後の座標から元画像の座標を求める部分なわけですが、とりあえず考え方を書いてみます。
基本的には2次元座標上の点から線分への垂線を求める事で、今見ている点が辺のどの位置にあたるのかを求める事が出来ます。
ですので、矩形を前提とするならば上辺と左辺、夫々の垂線との接触座標を求め、その座標がその辺のどの位置なのか、から元画像のX,Yを求める事が出来ます。
実際には三角分割を行えば実はもっと簡単にもとまる事が後からわかったのですが、それは後の祭りw
とりあえず三角分割する場合は、三角形の各頂点が元画像の座標のどの辺りに当たるのかを覚えておいてから、三角形の一辺がXのラインと水平になるように分割し、後は現在のスキャンラインが三角形のどの位置にあるかから比率で元画像の座標を求める事が出来ます。
多分こっちの方がずっと簡単だとは思いますw
[20090930]
一ヶ月位前になるが、上司から2DCGの回転描画ルーチンを作成するよう言われた。
無論私は色々とぐぐってみたのだが、どうも具体的な方法を書いているサイトが見あたらなかったのでこれから2回位にわけて私が実装した方法を書いてみたいと思う。
その前に、2DCGの回転描画の必要性についてなんだけど、実のところ私の場合では実際には要らないんじゃないか?と今でも思わずにはいられない。
というのも、単に矩形をディスプレイ上に回転表示するだけという事なのでPlgBltで事足りるのだ。
実際回転描画ルーチンを実装するまではPlgBltで描画していたのだし、PlgBltが上手く機能しないカードを今のところ見ていないので結構多くの場合にPlgBltで十分なんじゃなかろうか?と思っているのだがどうなんだろう?
まぁともあれ、社内用ツールではなく納品する為の物なのでどんな環境でも動く事が保証されてるわけじゃないPlgBltを嫌ったようで、2DCG回転ルーチンを書かされる羽目になったわけだ。
で、回転なんだけど、どうやって実装すれば良いかをまず考えてみて欲しい。
もし元画像の各ピクセルに単純に回転計算を施して描画すれば済むじゃん、と思った人はきっと実際に回転描画ルーチンを実装した事の無い人だろう。
じつのところ、それでは上手く行かないのだ。
回転計算すると当然座標に小数部が出てくるわけなんだけど、実際の画面には小数点のついたピクセル座標なんてものは存在しない。
従って、単純にピクセルに座標回転計算を施しただけでは微妙な計算誤差によりほぼ必ず微妙に穴が空いた画像になる。
ではどうすれば良いのか?
それをこれから書いていく。

さて、ピクセルに回転計算を施しただけでは上手く行かない事はわかったと思うが、では回転計算は要らないのか?
無論そんな事はない。
最初にやらなければいけないのはやっぱり回転計算なのだ。
回転する画像データの4頂点に対して移動/拡大/回転/フリップなどの計算をまず施しておく。
わかっていると思うが、これらの計算は順序に注意しなければならない。
座標移動を施してから回転させると、移動座標ごと回転する。
それが目的なら構わないが、回転と移動とは別々に管理したい場合は拡大縮小、回転を計算した後で移動を行わなければならない。
ちなみに拡大縮小と回転は同時に行う事が出来る。
単純に回転計算でsin/cosを行う際に拡大/縮小率をかけてやればよい。
void rotate(double degree) {
//	標準のsinとかはradianベースなのでradianに変換しなければならない
	double rad ;
	rad = degree * 0.017453292519943295769236907684886 ;
	para[0][0] = cos(rad) ;
	para[1][0] = sin(rad) ;
	para[0][1] = sin(rad) * - 1 ;
	para[1][1] = cos(rad) ;
}

//	XY夫々の拡大率を指定してマトリクスを初期化(2x2)
void scale(double xScale, double yScale) {
	para[0][0] = xScale ;
	para[0][1] = 0 ;
	para[1][0] = 0 ;
	para[1][1] = yScale ;
}

//	現在の回転マトリクスに拡縮要素をかけあわせる
void addScaleAttribute(double xScale, double yScale) {
	para[0][0] *= xScale ;
	para[0][1] *= yScale ;
	para[1][0] *= xScale ;
	para[1][1] *= yScale ;
}
こんな感じのmatrix計算ルーチンを作ってやれば簡単だろう。
多分ここまでは誰でも出来ると思うので、この辺りはサクサク行こう。
頂点を回転させた後は、その頂点が描く描画範囲を割り出す作業に入る事になる。
つまり頂点座標をラスタライズ処理するわけだ。
という辺りで次回にまわしたいと思うwww
[20090928]
最近私が経験した失敗談を書いてみる。

InvalidateRectをして、画面が更新されないなぁと思って調べてみたらメッセージが沢山溜まっていてWM_PAINTがきてなかった、という事があった。
これの対処の為にUpdateWindowを差し入れてみたんだが、これが失敗の元だった。
UpdateWindowは、それを実行した段階でWM_PAINTを強制的に実行するわけなんだが、ちょっと待って欲しい。
元々WM_PAINTがきてないのはメッセージが沢山溜まっていた為なんだから、実際にはそっちをなんとかしないといけなかったんだけど、対処療法的にUpdateWindowを入れてしまったもんだから表面上は上手い事動いているように見えても裏はすごい事になってしまっていた。
もうひっきりなしにメッセージが発行されまくり、しかも(比較的重い処理である)WM_PAINTが頻繁に実行されてしまうもんだから実行速度は格段に落ちていき、しかもどこかでメッセージ処理が滞ってしまうと途端に処理されないメッセージの山が溜まっていく事になる。
実際、ちょっと重い処理を実行させてしまうとメッセージ処理のせいでしばらく止まってしまう状態になってしまった。
結局のところ、無駄なメッセージ発行をある程度減らし、その上でUpdateWindowを全部取っ払ってやると嘘のようにスムーズに動くようになった。
つまるところ、その場を対処する為にUpdateWindowをしたのがそもそもの失敗であり、何かに対して対処する場合はその場しのぎではなく根本の原因を取り除かないと結局上手く行かない、という話でした。
[20090807]
並んでいるオブジェクトを範囲選択する為にラバーバンドを実装する事になって、エクスプローラーみたいな中が青いラバーバンドを簡単に作ってみたかったのでレイヤーウィンドウを使って実装してみた。
思った通り、意外と簡単に見た目の良いラバーバンド効果が実装できたんだけど、問題点が1つあった。
ラバーバンドをウィンドウで実装しているせいで、ラバーバンドが出ている時にはアプリケーションのウィンドウが非アクティブになってしまうのだw
これってEnableWindowでラバーバンドウィンドウをDisableにしてやれば問題無くなったりしないかなぁ?
まぁ、ラバーバンドが終わればアクティブに戻るのでそれ程の問題でもないんだけど、見た目がね。
ちなみにWS_CHILDをつければいいじゃんというのは無い。
何故ならチャイルド属性を持ったレイヤーウィンドウというのはどうやら作れないっぽいから。
WS_EX_LAYERDを指定している時にWS_CHILDを指定するとCreateWindowExはNULLを返す。
GetLastErrorをとってもエラーらしきエラーコードは返さない(操作は正常に終了した、になる)
[20090806]
何故だかわからないが、タイトルバーにタイトルが出ないようにしたレイヤーウィンドウ(オーナーを持たせたりWS_EX_TOOLWINDOW属性を持たせたり)を複数作ると、どんな内容を描画しようとしていても真っ白のウィンドウになる。
これが、タイトルバーに出てしまう、普通の、オーナーを持たないポップアップ等のウィンドウだと複数作っても普通に表示されるのだが、タイトルバーに出さないようにしようとすると途端に真っ白になる。
原因はわからないのだけど、これこのままだと不便だなぁ。
まぁカラーキー等を使って色々と出来るのは出来るんだけど、複数作れた方が絶対楽なんだけどなぁw
[20090802]
デザイナーさんにグラフィック作ってもらう為の素材として、プログラムで書いてる部品の一部をビットマップで出そうとしたんだけどCreateDIBSectionで作ったHBITMAPいくら試してもクリップボードにちゃんと入らない。
その時は結局CreateCompatibleBitmapで同サイズのDDBを作ってCreateDIBSectionで作ったビットマップからコピーして、そのDDBをクリップボードに入れたら普通に使えたんだけど、結局多分CreateDIBSectionで作ったHBITMAPってのは何かシステムに特殊な意味を持つ値なのだろう。
そういえば似たような事例がプロセスハンドルでもあった。
GetCurrentProcessで得られるハンドルはHANDLE型ではあるが擬似ハンドルで、みてみると大抵同じ値になっていた。
なのでそのままプロセスハンドルとして使うとちょっと挙動がおかしくなる場面もあったのだがもしかしたらCreateDIBSectionで得られるハンドルも普通とはちょっと違うのかも?
まぁ、値自体は特殊な定数とかそういう物ではないのでハンドルが実際に指しているオブジェクトが通常のHBITMAPが指している物とは違うとかそういう事なのかもしれないけど。
(確か、ハンドルってのはなにかのポインタだった気がする)
[20090725]
マニフェストファイルでdependentAssemblyを設定し、Common-ControlsのVer6を使うように指定すると、何故かプログレスバーでスムーススタイルを設定していてもスムース表示にならない。
これってXPのテーマか何かと関係あるんだろうか?
というか、この状態でプログレスバーをスムースで表示するにはどうするんだ?
HOME NEXT
copyright © 2005 drednote(Mr.Ty) all rights reserved.

Template By innerlife02

RSS1.0 ,
RSSフィード

応援バナー

検索フォーム

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。