2023/10/30(月) [n年前の日記]
#1 [hsp][python] HGIMG3とビットマップフォント画像の作り方を勉強中
Windows10 x64 22H2 + HSP 3.7 beta7 で、HGIMG3 について勉強中。
HGIMG3 というのは、DirectX8 を使って画面描画をするプラグイン、という説明でいいのだろうか。
昨日は hsp3dish という描画プラグインを使って色々試してたけど、OpenGL と DircetX のどちらを使って描画してるのか分からなくて…。HGIMG3 なら間違いなく DirectX を使ってくれるのではないかなと思えてきたので試用してみることにした。
HGIMG3 というのは、DirectX8 を使って画面描画をするプラグイン、という説明でいいのだろうか。
昨日は hsp3dish という描画プラグインを使って色々試してたけど、OpenGL と DircetX のどちらを使って描画してるのか分からなくて…。HGIMG3 なら間違いなく DirectX を使ってくれるのではないかなと思えてきたので試用してみることにした。
◎ ビットマップフォント画像を作りたい :
HGIMG3 プラグインで文字表示をするためには、ビットマップフォントがずらりと並んだ画像が必要になるらしい。
一応、HSP に同梱されている素材集、hsptv\ の中に、fontchr.png というビットマップフォント画像があるので、コレを使わせてもらえばビットマットフォントの描画/表示はできる。それで済ませてしまってもいいのだけど。
でも、せっかくだから、自分でフォント画像を作りたいよなと。そのあたりの作業を試してみた。
まずは自由に使えるビットマップフォント画像を入手しないといけない。
幸い、昔、MZ-700 に似た感じのフォントを自分で作ったことがあるので、まずはそれを使ってみることにした。自分で1ドットずつ打って作った画像だからライセンス面は問題無いはず。CC0 / Public Domain ってことで。使えそうなら自由に使ってください。
_pet2015.png (8x8 bitmap font)
このままだと小さいので、ドットエディタ EDGE2 で開いて、2倍に拡大して16x16のフォントにした。更に、不要な文字は削除して、文字の配置を変えてみた。
_pet2015_orig_16x16.png (16x16 bitmap font)
せっかくビットマップフォントを使うので、縁取りをしたい。そのためには各文字の周辺に隙間が必要。でも、1文字ずつ手作業でずらしていく作業なんてやってられないので、Python スクリプト + Pillow を使って自動化する。16x16個の文字が並んでるはずの画像を読み込んで、各文字の間に指定したドット数で隙間を入れる処理を書いてみた。動作環境は Windows10 x64 22H2 + Python 3.10.10 + Pillow 10.1.0。
_fontpadding.py
使い方は以下。
以下のような画像になった。
元画像と比べれば隙間が空いてることがわかる。
ドットエディタ EDGE2 を使って文字の周りに縁取りをする。イメージ → 効果 → 指定色に縁を加える、を選ぶ。更に、上下左右が繋がりそうな文字はドット修正。背景色は透過色扱いにする。
こんな感じになった。
_pet2015_border_20x20.png (20x20 bitmap font)
再度書くけど、CC0 / Public Domain ってことで。使えそうなら自由に使ってください。
一応、HSP に同梱されている素材集、hsptv\ の中に、fontchr.png というビットマップフォント画像があるので、コレを使わせてもらえばビットマットフォントの描画/表示はできる。それで済ませてしまってもいいのだけど。
でも、せっかくだから、自分でフォント画像を作りたいよなと。そのあたりの作業を試してみた。
まずは自由に使えるビットマップフォント画像を入手しないといけない。
幸い、昔、MZ-700 に似た感じのフォントを自分で作ったことがあるので、まずはそれを使ってみることにした。自分で1ドットずつ打って作った画像だからライセンス面は問題無いはず。CC0 / Public Domain ってことで。使えそうなら自由に使ってください。
このままだと小さいので、ドットエディタ EDGE2 で開いて、2倍に拡大して16x16のフォントにした。更に、不要な文字は削除して、文字の配置を変えてみた。
せっかくビットマップフォントを使うので、縁取りをしたい。そのためには各文字の周辺に隙間が必要。でも、1文字ずつ手作業でずらしていく作業なんてやってられないので、Python スクリプト + Pillow を使って自動化する。16x16個の文字が並んでるはずの画像を読み込んで、各文字の間に指定したドット数で隙間を入れる処理を書いてみた。動作環境は Windows10 x64 22H2 + Python 3.10.10 + Pillow 10.1.0。
_fontpadding.py
""" Load font image and padding. Usage : fontpadding.py INFILE OUTFILE PADDINGX PADDINGY Windows10 x64 22H2 + Python 3.10.10 64bit """ import sys from PIL import Image def main(): if len(sys.argv) != 5: print("Usage : fontpadding.py INFILE OUTFILE PADDINGX PADDINGY") sys.exit() infile = sys.argv[1] outfile = sys.argv[2] padx = int(sys.argv[3]) pady = int(sys.argv[4]) print(f"infile : {infile}") print(f"outfile : {outfile}") print(f"padding : {padx}, {pady}") im = Image.open(infile).convert("RGB") iw, ih = im.size print(im.format, iw, ih, im.mode) fw = iw / 16 fh = ih / 16 dw = iw + 16 * padx dh = ih + 16 * pady nim = Image.new("RGB", (dw, dh)) buf = [] for y in range(16): for x in range(16): x0 = x * fw y0 = y * fh im2 = im.crop((x0, y0, x0 + fw, y0 + fh)) tx = int(x * (fw + padx) + (padx / 2)) ty = int(y * (fh + pady) + (pady / 2)) nim.paste(im2, (tx, ty)) nim.save(outfile) if __name__ == '__main__': main()
使い方は以下。
python fontpadding.py INFILE OUTFILE n m example: python fontpadding.py in.png out.png 4 4
以下のような画像になった。
元画像と比べれば隙間が空いてることがわかる。
ドットエディタ EDGE2 を使って文字の周りに縁取りをする。イメージ → 効果 → 指定色に縁を加える、を選ぶ。更に、上下左右が繋がりそうな文字はドット修正。背景色は透過色扱いにする。
こんな感じになった。
再度書くけど、CC0 / Public Domain ってことで。使えそうなら自由に使ってください。
◎ ビットマップフォント画像を作りたい。その2 :
上記のビットマップフォントを使って済ませてもいいのだけど、もうちょっとオシャレな感じのフォントが欲しくなってきた。ゲーム用素材が公開されている OpenGameArt で、ビットマップフォントが公開されていたりしないかな…。
_OpenGameArt.org
「bitimap font」で検索しつつ、ライセンスは CC0 で絞ってみたら、イイ感じのフォントがいくつかあるようで…。以下のフォントがなんだか良さそう。ライセンスも CC0 なので改変も自由だし、コレを使わせてもらおうか…。ありがたや。
_Boxy Bold Font | OpenGameArt.org
EDGE2 で開いて、文字の配置をASCIIコードに合わせた感じにしてみた。また、小文字が無かったので、ドットを打ってテキトーに追加。せっかくだから置いておきます。元画像と同様に CC0 ってことで。
_boxy_bold_font_relayout_20x20.png (20x20 bitmap font)
「%」「&」「M」のあたりは横幅が大きくて、そこに合わせたら全体的に横長の画像に…。
_OpenGameArt.org
「bitimap font」で検索しつつ、ライセンスは CC0 で絞ってみたら、イイ感じのフォントがいくつかあるようで…。以下のフォントがなんだか良さそう。ライセンスも CC0 なので改変も自由だし、コレを使わせてもらおうか…。ありがたや。
_Boxy Bold Font | OpenGameArt.org
EDGE2 で開いて、文字の配置をASCIIコードに合わせた感じにしてみた。また、小文字が無かったので、ドットを打ってテキトーに追加。せっかくだから置いておきます。元画像と同様に CC0 ってことで。
「%」「&」「M」のあたりは横幅が大きくて、そこに合わせたら全体的に横長の画像に…。
◎ ビットマップフォント画像を作りたい。その3 :
他にもイイ感じのビットマップフォントはないものだろうか。そこでふと、BDFフォントの存在を思い出した。
BDFフォントと言うのは、昔の *NIX界隈で使われていたビットマップフォントのフォーマット。テキストファイルでドットの有無が記述されている。
_itouh: BDFについて
色んなBDFフォントがあるけれど、ググっているうちに東雲フォントが良さそうな気がしてきた。ライセンスは Public Domain とのことなので、画像にして使っても問題無いだろう…。ありがたや。
_東雲フォント - Wikipedia
_shinonome font family
shinonome-0.9.11p1.tar.bz2 を入手して解凍。bdf\ の中に、色々なサイズのbdfフォントが入っている。今回は、7x14ドットのフォントを使わせてもらおうかな…。
このbdfフォントを、一旦画像化しないといけない。ググったら、Webアプリとして BDF Font viewer というツールが公開されていたので利用させてもらうことにした。ありがたや。
_MRz-NET.org
BDF Font Viewer に、shnm7x14a.bdf を渡したところ、それらしいフォントが表示された。左下の「Glyph columns」を16にして、「Export PNG」をクリック。1文字7x14ドットのビットマップフォント画像が得られた。ただ、配置がちょっとおかしい。そこはEDGE2を使って適当に並び替えた。
前述の、各文字の間に隙間を入れる Pythonスクリプトを使って、隙間を入れておく。EDGE2 で縁取り。かつ、2倍に拡大。以下のような感じになった。
_shnm7x14ascii_border_18x32.png (18x32 bitmap font)
元のbdfフォントが Public Domain なので、コレも Public Domain ということで。
ここまで書いてから思い出したけど、bdf2bmp というツールを使えば、bdf から画像化できたのでは…? BDFフォントを扱うのは久しぶりだから、関連ツールのことをすっかり忘れていた…。
_bdf2bmp
_bdf2bmpの詳細情報 : Vector ソフトを探す!
_bmp2bdfの詳細情報 : Vector ソフトを探す!
BDFフォントと言うのは、昔の *NIX界隈で使われていたビットマップフォントのフォーマット。テキストファイルでドットの有無が記述されている。
_itouh: BDFについて
色んなBDFフォントがあるけれど、ググっているうちに東雲フォントが良さそうな気がしてきた。ライセンスは Public Domain とのことなので、画像にして使っても問題無いだろう…。ありがたや。
_東雲フォント - Wikipedia
_shinonome font family
shinonome-0.9.11p1.tar.bz2 を入手して解凍。bdf\ の中に、色々なサイズのbdfフォントが入っている。今回は、7x14ドットのフォントを使わせてもらおうかな…。
このbdfフォントを、一旦画像化しないといけない。ググったら、Webアプリとして BDF Font viewer というツールが公開されていたので利用させてもらうことにした。ありがたや。
_MRz-NET.org
BDF Font Viewer に、shnm7x14a.bdf を渡したところ、それらしいフォントが表示された。左下の「Glyph columns」を16にして、「Export PNG」をクリック。1文字7x14ドットのビットマップフォント画像が得られた。ただ、配置がちょっとおかしい。そこはEDGE2を使って適当に並び替えた。
前述の、各文字の間に隙間を入れる Pythonスクリプトを使って、隙間を入れておく。EDGE2 で縁取り。かつ、2倍に拡大。以下のような感じになった。
元のbdfフォントが Public Domain なので、コレも Public Domain ということで。
ここまで書いてから思い出したけど、bdf2bmp というツールを使えば、bdf から画像化できたのでは…? BDFフォントを扱うのは久しぶりだから、関連ツールのことをすっかり忘れていた…。
_bdf2bmp
_bdf2bmpの詳細情報 : Vector ソフトを探す!
_bmp2bdfの詳細情報 : Vector ソフトを探す!
◎ HGIMG3でHello World :
ビットマップフォント画像が作れたので、HGIMG3 で文字表示をしてみたい。とりあえず、Hello World と表示するだけのソースを書いてみる。
_02_helloworld_hgimg3.hsp
使用画像は以下。どれかしら1つで良い。
_font.png
_font2.png
_font3.png
以下のような画面になった。
せっかくだから、フォント画像を変更した際の画面も載せておく。印象が結構変わる。
文字色については、ビットマップフォント画像上で固定されているので、color命令を使って文字色を変えることはできない。
フォント用画像内の RGB=(0,0,0) を透明色として扱っているのか、それとも、フォント用画像にアルファチャンネルも含めてあるのかで、テクスチャ読み込み用の命令が違ってくるらしい。
_02_helloworld_hgimg3.hsp
; hgimg3 Hello world #include "hgimg3.as" #packopt name "02_helloworld_hgimg3" ; file name #packopt type 0 ; generate ".exe" hgini ; initialize hgimg3 ; initialize custom bitmap font setfont 20, 20, 18, 1 ; 20x20 font ; setfont 18, 32, 16, 1 ; 18x32 font ; load bitmap font image ; * texload : RGB=(0,0,0) is transparent. alpha channel not support. ; * texload2 : alpha channel support. texload "font.png" ; texload "font2.png" ; texload "font3.png" clscolor $4080c0 ; set clear color *mainloop ; ESC to exit stick k if k & 128 : goto *job_end hgdraw ; draw start ; draw text x = 100 y = 50 fprt "Hello World (HGIMG3)", x, y hgsync 15 ; draw end and wait goto *mainloop *job_end hgbye ; release HGIMG3 plugin end
使用画像は以下。どれかしら1つで良い。
_font.png
_font2.png
_font3.png
以下のような画面になった。
せっかくだから、フォント画像を変更した際の画面も載せておく。印象が結構変わる。
- HGIMG3 を使う時は、ソースの最初のほうで #include "hgimg3.as" と書く。
- hgini を呼んで、HGIMG3 を初期化する。
- hgdraw と hgsync を書いて、その間で描画処理を書く。
- hgsync N で、N ミリ秒ほど時間待ちをする。
- setfont で、ビットマップフォントの1文字あたりのサイズや、1文字書くたびに何ドット右に移動するか、抜き色の無し/有りを設定する。
- setfont を呼んだ直後に、textload もしくは texload2 でビットマップフォント画像を読み込む。
- fprt でビットマップフォントを使って文字を描画。
文字色については、ビットマップフォント画像上で固定されているので、color命令を使って文字色を変えることはできない。
フォント用画像内の RGB=(0,0,0) を透明色として扱っているのか、それとも、フォント用画像にアルファチャンネルも含めてあるのかで、テクスチャ読み込み用の命令が違ってくるらしい。
- texlaod : RGB=(0, 0, 0) を透明色として扱う。アルファチャンネルは無視する
- texload2 : アルファチャンネルが反映される
◎ 画像を描画 :
画像を描画してみる。せっかくだから、TIC-80起動時に読み込まれているサンプルと同様に、カーソルキーでキャラを移動できるプログラムにしてみる。
_03_image_draw.hsp
使用画像は以下。
_chara.png
_font.png
実行すると以下のような感じ。
HGIMG3 で画像を描画するには、hgrotate を使うらしい。拡大縮小回転描画ができる。
尚、描画時には、どのテクスチャを使うのかテクスチャIDを渡さないといけない。texload か texload2 を使って画像を読み込んだ直後、stat という変数に割り当てられたテクスチャIDが入っているそうなので、その値(テクスチャID)を別の変数に保存しておく。
_03_image_draw.hsp
; hgimg3 image draw (hgrotate) sample. #include "hgimg3.as" #include "d3m.hsp" #packopt name "03_image_draw" ; file name #packopt type 0 ; generate ".exe" #define TEXFILE "chara.png" #define FONTFILE "font.png" #pack TEXFILE #pack FONTFILE #define KB_ESC $00080 #define KB_LEFT $00001 #define KB_UP $00002 #define KB_RIGHT $00004 #define KB_DOWN $00008 #define KB_CURSOR (KB_LEFT | KB_UP | KB_RIGHT | KB_DOWN) screen 0, 512, 288, 0 ; initialize screen wdw_w = ginfo_winx ; get window size wdw_h = ginfo_winy hgini ; initialize hgimg3 ; load texture ; * texload : alpha channel not support ; * texload2 : alpha channel support texload2 TEXFILE texid = stat ; get texture ID texw = 16 texh = 16 ; init bimap font, load font texture setfont 20, 20, 18, 1 ; 20x20 font texload FONTFILE clscolor $4080c0 ; set clear color x = wdw_w / 2 y = wdw_h / 2 count = 0 time_start = d3timer() *mainloop ; get FPS tm = d3timer() - time_start fps = d3getfps() stick k, KB_CURSOR ; check keyboard if k & KB_ESC : goto *job_end ; ESC key to exit ; cursor key to move spd = 4 if k & KB_LEFT : x -= spd if k & KB_RIGHT : x += spd if k & KB_UP : y -= spd if k & KB_DOWN : y += spd ; ---------------------------------------- ; draw start hgdraw ; draw image gmode gmode_rgb0, texw, texh ; set src size pos x, y ; set position idx = (count / 15) & 1 src_x = texw * idx src_y = 0 scale = 4.0 rot = 0.0 dst_w = int(double(texw) * scale) dst_h = int(double(texh) * scale) hgrotate texid, src_x, src_y, rot, dst_w, dst_h ; draw texture ; draw text gmode gmode_rgb0 tx = (wdw_w / 2) - 20 * 9 ty = 12 fprt strf("[%dx%d] %d/60FPS", wdw_w, wdw_h, fps), tx, ty hgsync 15 ; draw end and wait count++ goto *mainloop *job_end hgbye ; release HGIMG3 plugin end
使用画像は以下。
_chara.png
_font.png
実行すると以下のような感じ。
HGIMG3 で画像を描画するには、hgrotate を使うらしい。拡大縮小回転描画ができる。
尚、描画時には、どのテクスチャを使うのかテクスチャIDを渡さないといけない。texload か texload2 を使って画像を読み込んだ直後、stat という変数に割り当てられたテクスチャIDが入っているそうなので、その値(テクスチャID)を別の変数に保存しておく。
[ ツッコむ ]
以上です。