2024/02/06(火) [n年前の日記]
#2 [basic] FreeBASICで反転描画。その2
Windows10 x64 22H2 + FreeBASIC 1.10.1 32bit で、標準機能のグラフィック描画で反転描画する方法について調べてる。
_昨日 は、公式掲示板で紹介されていた、色々な実装を動作確認していたわけだけど。その中の imgput() がイイ感じだなと…。
_Put function that does simple transformations - freebasic.net
ただ、透明色を扱わない仕様だったので、透明色有りで動くようにできないかと修正を試みた。
_昨日 は、公式掲示板で紹介されていた、色々な実装を動作確認していたわけだけど。その中の imgput() がイイ感じだなと…。
_Put function that does simple transformations - freebasic.net
ただ、透明色を扱わない仕様だったので、透明色有りで動くようにできないかと修正を試みた。
◎ ソース :
実処理部分。オリジナル版と混ざるとアレなので、サブルーチン名は imgput() から imgputt() にしておいた。
_imgputt.bi
imgputt()の使用サンプル。
_imgputt_test.bas
使用画像。
_sprite_24bit.bmp
_sprite_16bit.bmp
_sprite_8bit.bmp
fbc imgputt_test.bas でコンパイル。imgputt_test.exe を実行。
RGB = (255, 0, 255) の部分が透明になっている。
_imgputt.bi
imgputt()の使用サンプル。
_imgputt_test.bas
' imgput() sample. RGB = (255, 0, 255) is transparent #include "imgputt.bi" #define BPP 32 '#define BPP 16 '#define BPP 8 screenres 512, 288, BPP Dim As Any Ptr p = ImageCreate(101, 101) Select Case BPP Case 8 : Bload "sprite_8bit.bmp", p : color 16, 16 : cls Case 16 : Bload "sprite_16bit.bmp", p Case 32 : Bload "sprite_24bit.bmp", p End Select Dim As Integer mode = 0 ' 0 Trans, 1 Pset ' Draw imgputt( p, , 10 + 120 * 0, 10, 0, mode) imgputt( p, , 10 + 120 * 1, 10, 90, mode) imgputt( p, , 10 + 120 * 2, 10, 180, mode) imgputt( p, , 10 + 120 * 3, 10, 270, mode) imgputt( p, , 10 + 120 * 0, 130, TRANSFORM_HFLIP, mode ) imgputt( p, , 10 + 120 * 1, 130, TRANSFORM_VFLIP, mode ) imgputt( p, , 10 + 120 * 2, 130, TRANSFORM_D1FLIP, mode ) imgputt( p, , 10 + 120 * 3, 130, TRANSFORM_D2FLIP, mode ) imagedestroy p sleep
使用画像。
_sprite_24bit.bmp
_sprite_16bit.bmp
_sprite_8bit.bmp
fbc imgputt_test.bas でコンパイル。imgputt_test.exe を実行。
RGB = (255, 0, 255) の部分が透明になっている。
◎ ベンチマークを取ってみた :
せっかくだから、Put() と比べてどのくらい遅いのか調べてみた。
また、ついでなので、昨日自分が書いた、縦1ライン、もしくは横1ライン毎に Put() を使って逆方向に描画する版( PutEx() )も測ってみた。
_putex.bi
_imgputt_test2.bas
fbc imgputt_test2.bas でコンパイル。imgputt_test2.exe を実行。
水平反転のみ、垂直反転のみ、水平垂直反転、の3つを測定。
フォントが小さくて読めないかもしれないけれど、大体以下のような結果になった。
imgputt() は、大体5倍ぐらい遅い。どの反転描画も似たような処理をするので、処理速度は安定している。
ライン単位で Put() を呼んでいく PutEx() はかなり遅いのではないかと思ってたけど、意外とそうでもなかった。imgputt() は5倍遅いけど、PutEx() の水平反転は6倍ちょっと程度。そんなに悪くない。垂直反転に至っては Put() の2倍程度で処理できてるので、5倍遅い imgputt() よりも処理が速かった。これは意外だった。
ただ、PutEx() で水平垂直反転をすると、最悪な結果になる。135倍遅いのは、さすがに…。おそらく、Put() を1回呼ぶたびに、画面をオーバーしてないか等を調べていくのだろうけど、それを1ドットずつやってたら話にならないよなと…。
また、ついでなので、昨日自分が書いた、縦1ライン、もしくは横1ライン毎に Put() を使って逆方向に描画する版( PutEx() )も測ってみた。
_putex.bi
_imgputt_test2.bas
#include "imgputt.bi" #include "putex.bi" #define BPP 32 '#define BPP 16 '#define BPP 8 screenres 512, 288, BPP Dim As Any Ptr p = ImageCreate(101, 101) Select Case BPP Case 32 : Bload "sprite_24bit.bmp", p Case 16 : Bload "sprite_16bit.bmp", p Case 8 : Bload "sprite_8bit.bmp", p : color 16, 16 : cls End Select Dim As Double starttime, t0, t1, t2 Dim As Integer max_count = 3000 Sub sub1(ByVal max_count As Integer, ByVal p As Any Ptr) For i As Integer = 0 To max_count Put (10, 10), p, Trans ' Put (10, 10), p, Pset Next i End Sub Sub sub2(ByVal max_count As Integer, ByVal p As Any Ptr) For i As Integer = 0 To max_count 'imgputt( p, , 130, 10, TRANSFORM_HFLIP, 0 ) 'imgputt( p, , 130, 10, TRANSFORM_VFLIP, 0 ) imgputt( p, , 130, 10, TRANSFORM_HFLIP Or TRANSFORM_VFLIP, 0 ) Next i End Sub Sub sub3(ByVal max_count As Integer, ByVal p As Any Ptr) For i As Integer = 0 To max_count 'PutEx(10, 130, p, 0, 0, 101, 101, 1) 'PutEx(10, 130, p, 0, 0, 101, 101, 2) PutEx(10, 130, p, 0, 0, 101, 101, 3) Next i End Sub starttime = Timer ScreenLock sub1(max_count, p) ScreenUnlock t0 = Timer - starttime sleep 1000 starttime = Timer ScreenLock sub2(max_count, p) ScreenUnlock t1 = Timer - starttime sleep 1000 starttime = Timer ScreenLock sub3(max_count, p) ScreenUnlock t2 = Timer - starttime sleep 1000 Print "Put : " & t0 & " sec (100%)" Print "imgputt : " & t1 & " sec (" & int((t1 / t0) * 100) & "%)" Print "PutEx : " & t2 & " sec (" & int((t2 / t0) * 100) & "%)" imagedestroy p sleep
fbc imgputt_test2.bas でコンパイル。imgputt_test2.exe を実行。
- imgputt() は、メモリからメモリに値をコピーするものとして処理をしている。
- PutEx() は、横1ライン、もしくは縦1ライン毎に、Put() を使って逆方向に描画していく。水平垂直反転の時だけ、1ドット単位で Put() を呼んで描画する。
水平反転のみ、垂直反転のみ、水平垂直反転、の3つを測定。
フォントが小さくて読めないかもしれないけれど、大体以下のような結果になった。
- 水平反転のみ、かつ、透明色有効の場合、Put() と比べて、imgputt() は5倍遅い。PutEx() は6倍遅い。
- 垂直反転のみ、かつ、透明色有効の場合、Put() と比べて、imgputt() は5倍遅い。PutEx() は2倍遅い。
- 水平垂直反転、かつ、透明色有効の場合、Put() と比べて、imgputt() は5倍遅い。PutEX() は135倍遅い。
imgputt() は、大体5倍ぐらい遅い。どの反転描画も似たような処理をするので、処理速度は安定している。
ライン単位で Put() を呼んでいく PutEx() はかなり遅いのではないかと思ってたけど、意外とそうでもなかった。imgputt() は5倍遅いけど、PutEx() の水平反転は6倍ちょっと程度。そんなに悪くない。垂直反転に至っては Put() の2倍程度で処理できてるので、5倍遅い imgputt() よりも処理が速かった。これは意外だった。
ただ、PutEx() で水平垂直反転をすると、最悪な結果になる。135倍遅いのは、さすがに…。おそらく、Put() を1回呼ぶたびに、画面をオーバーしてないか等を調べていくのだろうけど、それを1ドットずつやってたら話にならないよなと…。
◎ Put()のソースを眺めてみた :
それにしても、標準描画機能の Put() は異様に速い。どういう処理をしているのだろう。github にC言語で書かれたソースがあったので眺めてみた。
_fbc/src/gfxlib2/gfx_put_trans.c at master - freebasic/fbc
fb_hPutTrans1C()、fb_hPutTrans2C()、fb_hPutTrans4C() があるけれど、それぞれ、色深度8bitモード(パレットモード)、16bitモード(RRRRRGGGGGGBBBB bit)、32bitモード(AARRGGBB byte)なのだろう。
やってることは、imgputt() とさほど変わらない印象。y と x でループを回して、1ドットずつ見ていって、値をコピーするかしないかを決めて、ポインタをしかるべき値で進める。まあ、そうなるよなあ…。
もしかして、+= ではなくて、++ をループ内で使ってるあたりが効いてるのだろうか?
_fbc/src/gfxlib2/gfx_put_trans.c at master - freebasic/fbc
fb_hPutTrans1C()、fb_hPutTrans2C()、fb_hPutTrans4C() があるけれど、それぞれ、色深度8bitモード(パレットモード)、16bitモード(RRRRRGGGGGGBBBB bit)、32bitモード(AARRGGBB byte)なのだろう。
やってることは、imgputt() とさほど変わらない印象。y と x でループを回して、1ドットずつ見ていって、値をコピーするかしないかを決めて、ポインタをしかるべき値で進める。まあ、そうなるよなあ…。
もしかして、+= ではなくて、++ をループ内で使ってるあたりが効いてるのだろうか?
[ ツッコむ ]
以上です。