一ヶ月位前になるが、上司から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