2024/02/10(土) [n年前の日記]
#2 [basic] FreeBASICで画像を拡大描画する方法を勉強中
FreeBASICで画像を拡大描画したい。QVGA(320x240)ぐらいの小さいサイズの画像バッファにCPUでアレコレを描画して、それをデスクトップ画面全体に拡大表示してみたい。
環境は Windows10 x64 22H2 + FreeBASIC 1.10.1 32bit。
環境は Windows10 x64 22H2 + FreeBASIC 1.10.1 32bit。
◎ 拡大時だけOpenGLを使う方法 :
公式掲示板(?)を眺めていたら、画像バッファにはCPUで描画しつつ、その画像バッファを拡大表示する時だけ OpenGL を使う方法が紹介されていた。そんなこともできるのか…。拡大表示だけでもハードウェアで処理してくれるならありがたい。CPUでデスクトップ全体にドットを打っていくのはそこそこ処理が重そうだし。
_Modern GL 2D game lib needed - freebasic.net
紹介されているソースの動作確認をしてみた。fbc gl2dscale_orig.bas でコンパイル。
_gl2dscale_orig.bas
ちょっと分かりづらいけれど、320x200の画面を、4倍のウインドウサイズ、1280x800 の大きさに拡大表示できている。
ScreenControl() で、SET_GL_2D_MODE と SET_GL_SCALE を指定して、ScreenRes() で、GFX_OPENGL を指定するのが肝らしい。
_SCREENCONTROL
_SCREENRES
注意点。FreeBASIC + OpenGL で描画する際は、最後に flip() を呼ぶことでダブルバッファを切り替えて、そこで描画結果が画面に表示されるのだけど、ループの中で flip() を呼んでやらないとハングアップするらしい。
_Modern GL 2D game lib needed - Page 2 - freebasic.net
さておき。これを使えば、デスクトップ画面全体に拡大表示してフルスクリーン表示をしているかのように見せられるのではないか。と思ったけれど甘かった。
_gl2dscale.bas
screencontrol(SET_GL_SCALE, n) で指定できる拡大率は、Integer(整数)しか受け付けないらしい…。Double で変数を用意して渡したらエラーになった。
拡大率を整数で指定することしかできないとなると、結構な領域がデスクトップ画面外にはみ出してしてまう状態もフツーにありそうだなと…。元画面をドット単位できっちり調整しながら作っても、ごっそり表示されない領域が出てきてしまうのでは…。もっとも、整数倍の表示なら、各ドットは綺麗にクッキリと等間隔で表示されるというメリットはありそう。
何か上手い方法はないものか。例えば、整数倍で拡大した際にできてしまう未使用領域を埋めてくれるような元画面サイズを計算で求めて、ウインドウサイズはそのサイズで指定するけど、描画範囲を本来想定していたサイズに限定して処理してやればいいのだろうか。デスクトップ画面の中に一回り小さな描画領域が表示されている状態になりそうではあるけれど…。
_Modern GL 2D game lib needed - freebasic.net
紹介されているソースの動作確認をしてみた。fbc gl2dscale_orig.bas でコンパイル。
_gl2dscale_orig.bas
ちょっと分かりづらいけれど、320x200の画面を、4倍のウインドウサイズ、1280x800 の大きさに拡大表示できている。
ScreenControl() で、SET_GL_2D_MODE と SET_GL_SCALE を指定して、ScreenRes() で、GFX_OPENGL を指定するのが肝らしい。
screencontrol(SET_GL_2D_MODE, OGL_2D_MANUAL_SYNC) screencontrol(SET_GL_SCALE, 4) screenres scrw, scrh, 32, , GFX_OPENGL
_SCREENCONTROL
_SCREENRES
注意点。FreeBASIC + OpenGL で描画する際は、最後に flip() を呼ぶことでダブルバッファを切り替えて、そこで描画結果が画面に表示されるのだけど、ループの中で flip() を呼んでやらないとハングアップするらしい。
_Modern GL 2D game lib needed - Page 2 - freebasic.net
さておき。これを使えば、デスクトップ画面全体に拡大表示してフルスクリーン表示をしているかのように見せられるのではないか。と思ったけれど甘かった。
_gl2dscale.bas
screencontrol(SET_GL_SCALE, n) で指定できる拡大率は、Integer(整数)しか受け付けないらしい…。Double で変数を用意して渡したらエラーになった。
拡大率を整数で指定することしかできないとなると、結構な領域がデスクトップ画面外にはみ出してしてまう状態もフツーにありそうだなと…。元画面をドット単位できっちり調整しながら作っても、ごっそり表示されない領域が出てきてしまうのでは…。もっとも、整数倍の表示なら、各ドットは綺麗にクッキリと等間隔で表示されるというメリットはありそう。
何か上手い方法はないものか。例えば、整数倍で拡大した際にできてしまう未使用領域を埋めてくれるような元画面サイズを計算で求めて、ウインドウサイズはそのサイズで指定するけど、描画範囲を本来想定していたサイズに限定して処理してやればいいのだろうか。デスクトップ画面の中に一回り小さな描画領域が表示されている状態になりそうではあるけれど…。
◎ CPUで拡大縮小 :
以下のやり取りで、CPUで計算して拡大縮小する方法が紹介されていた。途中から回転描画処理や3D描画処理に話が変わっていってしまうけど、最初のあたりは参考になりそう。
_Mini Image Scaler Demo - freebasic.net
固定小数点を使って処理してる事例が分かりやすくて参考になりそう。32bitのうち、整数部を12bit、小数部を20bitにして…。描画先のアドレスは1ドットずつ進めて、描画元の参照アドレスは固定小数点計算で求めていく模様。
デスクトップ画面全体に拡大表示できるか試してみた。fbc miniimagescalerdemo4.bas でコンパイル。
_imagescale2.bi (拡大縮小実処理を担当する ImageScale() )
_createsampleimage.bi (サンプル画像作成部分)
_miniimagescalerdemo4.bas ( ImageScale() を呼び出すサンプル)
AMD Ryzen 5 5600X上で、1920x1080 のデスクトップ画面に拡大表示する分には、CPU負荷はそれほどかかってないように見えた。非力なCPUで動かすとどうなるのかちょっと分からないけど…。
それでも、小さい画像バッファに色々書き込んでおいて、最後にデスクトップ全体に拡大表示する、といった使い方なら、1フレームに1回しか処理しないからどうにか使えるのではないかという気もする…。
このあたり、C言語で書いて FreeBASICのライブラリにできたら、もうちょっと処理速度を追求できるのではないかな…。もっとも、描画を速くしたいなら、ハードウェア描画ができる何かしらのライブラリを使えないか検討するのが妥当だろうか…。
_Mini Image Scaler Demo - freebasic.net
固定小数点を使って処理してる事例が分かりやすくて参考になりそう。32bitのうち、整数部を12bit、小数部を20bitにして…。描画先のアドレスは1ドットずつ進めて、描画元の参照アドレスは固定小数点計算で求めていく模様。
デスクトップ画面全体に拡大表示できるか試してみた。fbc miniimagescalerdemo4.bas でコンパイル。
_imagescale2.bi (拡大縮小実処理を担当する ImageScale() )
_createsampleimage.bi (サンプル画像作成部分)
_miniimagescalerdemo4.bas ( ImageScale() を呼び出すサンプル)
AMD Ryzen 5 5600X上で、1920x1080 のデスクトップ画面に拡大表示する分には、CPU負荷はそれほどかかってないように見えた。非力なCPUで動かすとどうなるのかちょっと分からないけど…。
それでも、小さい画像バッファに色々書き込んでおいて、最後にデスクトップ全体に拡大表示する、といった使い方なら、1フレームに1回しか処理しないからどうにか使えるのではないかという気もする…。
このあたり、C言語で書いて FreeBASICのライブラリにできたら、もうちょっと処理速度を追求できるのではないかな…。もっとも、描画を速くしたいなら、ハードウェア描画ができる何かしらのライブラリを使えないか検討するのが妥当だろうか…。
[ ツッコむ ]
以上です。