mieki256's diary



2023/10/30(月) [n年前の日記]

#1 [hsp][python] HGIMG3とビットマップフォント画像の作り方を勉強中

Windows10 x64 22H2 + HSP 3.7 beta7 で、HGIMG3 について勉強中。

HGIMG3 というのは、DirectX8 を使って画面描画をするプラグイン、という説明でいいのだろうか。

昨日は hsp3dish という描画プラグインを使って色々試してたけど、OpenGL と DircetX のどちらを使って描画してるのか分からなくて…。HGIMG3 なら間違いなく DirectX を使ってくれるのではないかなと思えてきたので試用してみることにした。

ビットマップフォント画像を作りたい :

HGIMG3 プラグインで文字表示をするためには、ビットマップフォントがずらりと並んだ画像が必要になるらしい。

一応、HSP に同梱されている素材集、hsptv\ の中に、fontchr.png というビットマップフォント画像があるので、コレを使わせてもらえばビットマットフォントの描画/表示はできる。それで済ませてしまってもいいのだけど。

でも、せっかくだから、自分でフォント画像を作りたいよなと。そのあたりの作業を試してみた。

まずは自由に使えるビットマップフォント画像を入手しないといけない。

幸い、昔、MZ-700 に似た感じのフォントを自分で作ったことがあるので、まずはそれを使ってみることにした。自分で1ドットずつ打って作った画像だからライセンス面は問題無いはず。CC0 / Public Domain ってことで。使えそうなら自由に使ってください。

pet2015.png
_pet2015.png (8x8 bitmap font)

このままだと小さいので、ドットエディタ EDGE2 で開いて、2倍に拡大して16x16のフォントにした。更に、不要な文字は削除して、文字の配置を変えてみた。

pet2015_orig_16x16.png
_pet2015_orig_16x16.png (16x16 bitmap font)


せっかくビットマップフォントを使うので、縁取りをしたい。そのためには各文字の周辺に隙間が必要。でも、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


以下のような画像になった。

pet2015_new_20x20.png

元画像と比べれば隙間が空いてることがわかる。

pet2015_orig_16x16.png


ドットエディタ EDGE2 を使って文字の周りに縁取りをする。イメージ → 効果 → 指定色に縁を加える、を選ぶ。更に、上下左右が繋がりそうな文字はドット修正。背景色は透過色扱いにする。

こんな感じになった。

pet2015_border_20x20.png
_pet2015_border_20x20.png (20x20 bitmap font)

再度書くけど、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
_boxy_bold_font_relayout_20x20.png (20x20 bitmap font)

「%」「&」「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
_shnm7x14ascii_border_18x32.png (18x32 bitmap font)

元のbdfフォントが Public Domain なので、コレも Public Domain ということで。

ここまで書いてから思い出したけど、bdf2bmp というツールを使えば、bdf から画像化できたのでは…? BDFフォントを扱うのは久しぶりだから、関連ツールのことをすっかり忘れていた…。

_bdf2bmp
_bdf2bmpの詳細情報 : Vector ソフトを探す!
_bmp2bdfの詳細情報 : Vector ソフトを探す!

HGIMG3でHello World :

ビットマップフォント画像が作れたので、HGIMG3 で文字表示をしてみたい。とりあえず、Hello World と表示するだけのソースを書いてみる。

_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

以下のような画面になった。

02_helloworld_hgimg3_ss01.png


せっかくだから、フォント画像を変更した際の画面も載せておく。印象が結構変わる。

02_helloworld_hgimg3_ss02.png

02_helloworld_hgimg3_ss03.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
    ; 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

実行すると以下のような感じ。

03_image_draw_ss01.gif


HGIMG3 で画像を描画するには、hgrotate を使うらしい。拡大縮小回転描画ができる。

尚、描画時には、どのテクスチャを使うのかテクスチャIDを渡さないといけない。texload か texload2 を使って画像を読み込んだ直後、stat という変数に割り当てられたテクスチャIDが入っているそうなので、その値(テクスチャID)を別の変数に保存しておく。

以上です。

過去ログ表示

Prev - 2023/10 - Next
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project