前回から結構間が空いてしまいましたが、これは更新を忘れていたから ではなくて…、いや、忘れてました (^^;;
今回は VOID DrawPolygon() のテクスチャ画像の「斜め読み」 の部分を固定少数点化して高速化を行います。と言っても、 基本的にやる事は同じで、違うのは
double tx,ty,tdx,tdy; // テクスチャ座標計算用
となっていた部分を
WORD tx,ty,tdx,tdy;
の様に double 型ではなくて WORD 型に変えて、後は 少数点をシフト演算で右にずらして(<<)足し算していくだけです。 まあ、具体的には下のソースを見れば分かると思います。 VOID DrawPolygon() 以外の関数は前回と同じです。
さて、どのくらい速くなるかですが、前回は MMX-P155 の マシンでは 22 FPS でしたが、今回は 82 FPS まで速くなりました(^^。 ただし、(当然ですが)精度が 16 bit になったため画像は荒くなります。
ちなみにエッジのスキャンをする VOID ScanLine() も固定少数化 すると少しは速くなりますが、ループ数が小さいので劇的には 速くならず、逆にエッジがガタガタになるので止めた方が良いです。
//--------------------------------------------
// ポリゴン描画関数 16bit 固定少数使用版
// 小数点第一桁の位置は右から 5 bit 目、つまり整数部は +-1024 の範囲
// この範囲を超えないように気を付けること
//
// Y 軸スキャン 固定少数使用で平均 82 FPS
VOID DrawPolygon(LPPOLYDATA lpPolyData, // ポリゴンデータ
LPSCANDATA lpScanData, // Y 軸スキャン用データのバッファ
LPBYTE lpDest, // 描画画面のバッファ
LONG nDestWidth, // 描画座標幅
LONG nDestHeight, // 描画座標高さ
LPBYTE lpTex, // テクスチャのバッファ
LONG nTexWidth, // テクスチャ幅
LONG nTexHeight // テクスチャ高さ
){
LONG x,y; // ループ用
LONG nStartY,nEndY; // 描画開始を開始する Y 座標、終了座標
LONG i,i2;
LONG maxX,minX; // エッジ座標の最大最小値
DWORD dwTexSize = (DWORD)(nTexHeight*nTexWidth); // テクスチャのサイズ
DWORD dwReadPoint; // テクスチャデータを読み込むアドレス
DWORD dwScanData,dwDest; // エッジの座標データと転送先のベースアドレス
// エッジの座標のスキャン
ScanLine(lpPolyData,lpScanData,nDestWidth,nDestHeight,&nStartY,&nEndY);
// 範囲外なら描画しない
if(nStartY >= nDestHeight || nEndY < 0) return;
// 転送先バッファとスキャンデータのベースアドレスセット
// 転送先バッファ(DIB)は上下が反転しているのに注意((nDestHeight-1-nStartY)の所)
dwDest = (DWORD)lpDest + (DWORD)((nDestHeight-1-nStartY)*nDestWidth);
dwScanData = (DWORD)lpScanData + (DWORD)(nStartY*sizeof(SCANDATA));
// nStartY から nEndY まで上から順に描画
for(y = nStartY; y <= nEndY; y++){
// エッジの(転送先画像(dwDest)上での)座標セット
minX = *(LPLONG)(dwScanData);
maxX = *(LPLONG)(dwScanData+4);
if(maxX >= 0){
// テクスチャ座標計算用変数(16 bit 固定少数)
WORD tx,ty,tdx,tdy;
// 初期テクスチャ座標セット (minTx,minTy) -> (tx,ty)
// 及び小数点の位置移動 (5 bit 分右に)
memcpy(&tx,(VOID*)(dwScanData+8),sizeof(WORD));
memcpy(&ty,(VOID*)(dwScanData+12),sizeof(WORD));
tx <<= 5;
ty <<= 5;
// 描画座標で x が 1 増加した時のテクスチャ座標での
// x と y の変位を計算
if(maxX != minX){
i2 = (maxX-minX)<<16; // DWORD -> WORD 変換
// x の変位 tdx = (maxTx-minTx)/(maxX-minX)
// 全体で見ると ( << 21 / << 16) = << 5 なので 5 bit 右へ小数点移動
i = ((*(LPLONG)(dwScanData+16)-*(LPLONG)(dwScanData+8))<<21)/i2;
memcpy(&tdx,&i,sizeof(WORD));
// y の変位 tdy = (maxTy-minTy)/(maxX-minX)
i = ((*(LPLONG)(dwScanData+20)-*(LPLONG)(dwScanData+12))<<21)/i2;
memcpy(&tdy,&i,sizeof(WORD));
}
else { // 一点の時
tdx = 0;
tdy = 0;
}
// 左側エッジ(minX)が 0 より小さいなら 0 になるまで回す
while(minX < 0){
minX++;
tx += tdx;
ty += tdy;
}
// 左から右に横に描画していく
maxX = min(nDestWidth-1,maxX);
for(x = minX; x <= maxX; x++){
// テクスチャデータを読み込む点を計算
dwReadPoint = (DWORD)(nTexHeight-1-(ty>>5))*nTexWidth+(tx>>5);
// コピー
if(dwReadPoint < dwTexSize) *(LPBYTE)(dwDest+x) = lpTex[dwReadPoint];
// テクスチャ座標移動
tx += tdx;
ty += tdy;
}
}
// バッファとスキャンデータのベースアドレス更新
dwDest -= nDestWidth;
dwScanData += sizeof(SCANDATA);
}
}