前回から結構間が空いてしまいましたが、これは更新を忘れていたから ではなくて…、いや、忘れてました (^^;;
今回は 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); } }