2023/09/13(水) [n年前の日記]
#1 [hsp] 疑似3D道路その10
_昨日
の続き。HSP 3.6 を使って、疑似3D道路が作れないか試しているところ。環境は Windows10 x64 22H2。
一応、BG/遠景を、仮想画面の解像度に合わせて縮小描画させつつスクロールできるようにはなったのだけど、目で見て分かるぐらいに処理落ちが増えてしまった。元画像から縮小しながら 1280x720 の面積で、多重スクロールのためにBGを2枚描画するのは、今時のCPUで処理しても厳しいものがあるのだなと…。
DircetX や OpenGL を使ってGPUに描画させればあっさり状況は変わりそうだけど、後々スクリーンセーバにしたいと考えているので…。HSP でスクリーンセーバを作る際、DirectX や OpenGL が使えるのかどうかがよく分からなくて、おそらくは CPU で真面目に計算して拡大縮小描画をしているのであろう gzoom命令を使ってるという…。
ここまで遅くなるのでは、何か策を打たないといけない気がする。
余談。上記の方針を立てて画像の再作成作業を始めたら、メインPCがブルースクリーン(BSOD)に。最近BSODは見かけなかったのだけどなあ…。ちょうど Windows Update のタイミングだったようで、そのあたりが影響してる気がする…。
一応、BG/遠景を、仮想画面の解像度に合わせて縮小描画させつつスクロールできるようにはなったのだけど、目で見て分かるぐらいに処理落ちが増えてしまった。元画像から縮小しながら 1280x720 の面積で、多重スクロールのためにBGを2枚描画するのは、今時のCPUで処理しても厳しいものがあるのだなと…。
DircetX や OpenGL を使ってGPUに描画させればあっさり状況は変わりそうだけど、後々スクリーンセーバにしたいと考えているので…。HSP でスクリーンセーバを作る際、DirectX や OpenGL が使えるのかどうかがよく分からなくて、おそらくは CPU で真面目に計算して拡大縮小描画をしているのであろう gzoom命令を使ってるという…。
ここまで遅くなるのでは、何か策を打たないといけない気がする。
- 多重スクロールは諦めて、BG1枚だけを描画することにする。そもそも遠景だから多重スクロールの効果も弱かったし。画像作成時も、前後2枚になるように切り出しをする作業が面倒臭かったし。
- 事前に、仮想画面の解像度種類分、BG画像を用意しておいて、メインループを回してる時は拡大縮小描画(gzoom)ではなく、ベタ転送(gcopy)を使って描画する。その分メモリは食うけど…。
余談。上記の方針を立てて画像の再作成作業を始めたら、メインPCがブルースクリーン(BSOD)に。最近BSODは見かけなかったのだけどなあ…。ちょうど Windows Update のタイミングだったようで、そのあたりが影響してる気がする…。
◎ テストプログラムを置いておく :
一応、2枚のBG画像を縮小描画しながらスクロールさせるテストプログラムを置いておく。
_bgscroll.hsp
使用画像は以下。
_bg_bg0.png
_bg_bg1.png
動作結果は以下。
今気づいたけど、奥側のBGレイヤーについては、RGB=(0,0,0) を透明色として扱う gmode gmode_rgb0 を使わずに、ベタ転送する gmode gmode_gdi を使ったほうが良かったのでは…? そうすれば、少しは処理時間が短くなったのでは…。いや、焼け石に水か…。
これまた今気づいたけど、手前側のBGレイヤーの下半分で、奥側のBGレイヤーは完全に隠されてしまうのだから、そこは奥側を描画しなくても良かったのでは…? そうすれば、少しは処理時間が短くなったのでは…。まあ、それも焼け石に水かな…。
考えてみたら、BGが1枚しかなくても、ラスタースクロール相当をすれば多重スクロールに見えるよな…。縦方向に多重スクロールさせないなら、それで十分かも。まあ、そういう画像を作らないといかんのだけど。
_bgscroll.hsp
; BGスクロールのテスト
;
; Left, Right, Up, Down key : 表示位置変更
; Z key : 仮想画面の解像度変更
;
; 2023/09/13 by mieki256
; 実画面解像度
#define SCR_W 640
#define SCR_H 360
; #define SCR_W 1280
; #define SCR_H 720
; #define SCR_W 1600
; #define SCR_H 900
; #define SCR_W 1200
; #define SCR_H 900
; #define SCR_W 1920
; #define SCR_H 1080
#define set_array_n2(%1, %2, %3, %4) \
%1(%2, 0) = %3 :\
%1(%2, 1) = %4 :
; 仮想画面解像度
dim vscr_size, 6, 2
set_array_n2 vscr_size, 0, 640, 360
set_array_n2 vscr_size, 1, 800, 450
set_array_n2 vscr_size, 2, 1280, 720
set_array_n2 vscr_size, 3, 320, 180
set_array_n2 vscr_size, 4, 480, 270
set_array_n2 vscr_size, 5, 512, 288
; set_array_n2 vscr_size, 6, 1920, 1080
vscr_size_idx = 0
VSCR_W_MAX = 1920
VSCR_H_MAX = 1080
; 同梱ファイル / bundled files
#define BG0_FILE "bg_bg0.png"
#define BG1_FILE "bg_bg1.png"
; #define BG0_FILE "bg_bg0_orig.png"
; #define BG1_FILE "bg_bg1_orig.png"
#pack BG0_FILE
#pack BG1_FILE
#packopt name "bgscroll" ; exe filename
#packopt type 0 ; generate ".exe"
#packopt xsize SCR_W
#packopt ysize SCR_H
; get windows size
screen 0, SCR_W, SCR_H, 0
gsel 0
screen_w = ginfo_winx
screen_h = ginfo_winy
cls 4
; init virtual screen buffer
vscrbufid = 1
buffer vscrbufid, VSCR_W_MAX, VSCR_H_MAX
dispw = vscr_size(vscr_size_idx, 0)
disph = vscr_size(vscr_size_idx, 1)
; load bg image
dim bgimgid, 2
dim bgw, 2
dim bgh, 2
dim bgfilename, 2
bgfilename(0) = BG0_FILE
bgfilename(1) = BG1_FILE
repeat 2
bgimgid(cnt) = 4 + cnt
buffer bgimgid(cnt), 4096, 2048
picload bgfilename(cnt)
bgw(cnt) = ginfo_winx
bgh(cnt) = ginfo_winy
loop
; init temporary image buffer
tmpid = 7
buffer tmpid, 4096, 4096
; bg scroll. 0.0 - 1.0
bg_x = 0.0
bg_y = 0.0
vscr_change = 0
nowframerate = 60.0
*mainloop
#define KEY_ESC 128
#define KEY_UP 2
#define KEY_DOWN 8
#define KEY_LEFT 1
#define KEY_RIGHT 4
#define KEY_Z 2048
#define KEY_X 4096
#define KEY_PRESS (KEY_UP + KEY_DOWN + KEY_LEFT + KEY_RIGHT)
stick k, KEY_PRESS
; ESC key to exit
if k & KEY_ESC : goto *jobend
; 仮想画面サイズを変更
if k & KEY_Z {
if vscr_change == 0 {
vscr_change = 1
vscr_size_idx = (vscr_size_idx + 1) \ length(vscr_size)
dispw = vscr_size(vscr_size_idx, 0)
disph = vscr_size(vscr_size_idx, 1)
}
} else {
vscr_change = 0
}
; check cursor key
spd = 1.0 / (nowframerate * 1.0)
if k & KEY_UP : bg_y -= spd
if k & KEY_DOWN : bg_y += spd
if k & KEY_LEFT : bg_x -= spd
if k & KEY_RIGHT : bg_x += spd
if bg_y < -1.0 : bg_y = -1.0
if bg_y > 1.0 : bg_y = 1.0
base_y = int(double(disph) * 0.5)
; 描画開始 / draw start
redraw 0
gsel vscrbufid
; 背景(遠景)を描画 / draw BG
draw_bg vscrbufid, bg_x, bg_y, bgimgid, bgw, bgh, dispw, disph, tmpid
; 仮想画面を実画面に転送
gsel 0
gmode gmode_gdi
if screen_w == dispw and screen_h == disph {
; 等倍で転送
pos 0, 0
gcopy vscrbufid, 0, 0, dispw, disph
} else {
; 拡大縮小して転送
xscale = double(screen_w) / double(dispw)
yscale = double(screen_h) / double(disph)
; if xscale < yscale : scale = xscale : else : scale = yscale
if xscale < yscale : scale = yscale : else : scale = xscale
dstw = int(double(dispw) * scale)
dsth = int(double(disph) * scale)
dstx = (SCR_W - dstw) / 2
dsty = (SCR_H - dsth) / 2
pos dstx, dsty
gzoom dstw, dsth, vscrbufid, 0, 0, dispw, disph, 0
}
; draw text
if 1 {
gsel 0
font "Arial", 16, 1, 2
objcolor 255, 255, 255
color 1, 1, 1
pos 4, 20
mes "Press cursor key or Z", 4
pos 4, 40
mes "Res:" + dispw + "x" + disph, 4
pos 4, 60
mes "bg_x, bg_y = " + bg_x + ", " + bg_y, 4
}
redraw 1 ; 描画終了 / draw end
await (1000 / int(nowframerate))
goto *mainloop
#module
#deffunc draw_bg int dstid, double bg_x, double bg_y, array bgimgid, array bgw, array bgh, int dispw, int disph, int tmpid
; BGを描画 / draw BG
;
; dstid : 描画先バッファID
; bg_x, bg_y : bg position. 0.0 - 1.0
; bgimgid : bg images buffer ID. array.
; bgw, bgh : bg width, height. array.
; dispw, disph : screen width, height
; tmpid : 作業バッファID
bx = bg_x
by = bg_y
if by < -1.0 : by = -1.0
if by > 1.0 : by = 1.0
repeat 2
i = (2 - 1) - cnt
bgid = bgimgid(i)
bw = bgw(i)
bh = bgh(i)
shiftx = bx
if i == 1 : shiftx *= 0.75
sx = int(double(bh / 4) * shiftx) \ bw
sy = int(double(bh / 4) * by) + (bh / 2) - (bh / 4)
sw = (bh / 2) * dispw / disph
sh = bh / 2
dx = 0
dy = 0
dw = dispw
dh = disph
if sx >= 0 and (sx + sw) < bw {
draw_by_gzoom dstid, dx, dy, dw, dh, bgid, sx, sy, sw, sh, tmpid, dispw, disph
} else {
if (sx + sw) > bw : sx = (sx - bw) \ bw
w = -sx
sw0 = w
sx0 = bw - w
dx0 = 0
dw0 = w * dw / sw
sw1 = sw - w
sx1 = 0
dx1 = dw0
dw1 = dw - dw0
draw_by_gzoom dstid, dx0, dy, dw0, dh, bgid, sx0, sy, sw0, sh, tmpid, dispw, disph
draw_by_gzoom dstid, dx1, dy, dw1, dh, bgid, sx1, sy, sw1, sh, tmpid, dispw, disph
}
loop
return
#global
#module
#deffunc draw_by_gzoom int dstid, int dstx, int dsty, int dstw, int dsth, int srcid, int srcx, int srcy, int srcw, int srch, int tmpid, int dispw, int disph
; 画面外にはみ出る分を考量して最小面積で画像を拡大縮小描画
;
; dstid : 描画先バッファID
; dstx, dsty, dstw, dsth : 描画先左上座標, 描画先サイズ
; srcid : 元画像バッファID
; srcx, srcy, srcw, scrh : 元画像左上座標, 元画像サイズ
; tmpid : 作業用イメージバッファID
; dispw, disph : 画面サイズ
dx = dstx
dy = dsty
dw = dstw
dh = dsth
sx = srcx
sy = srcy
sw = srcw
sh = srch
if dx >= dispw or (dx + dw) < 0 : return
if dy >= disph or (dy + dh) < 0 : return
if dx < 0 {
w = (-dx) * sw / dw
sx += w
sw -= w
dw += dx
dx = 0
}
if dy < 0 {
h = (-dy) * sh / dh
sy += h
sh -= h
dh += dy
dy = 0
}
if (dx + dw) > dispw {
dwd = (dx + dw) - dispw
swd = dwd * sw / dw
sw -= swd
dw -= dwd
}
if (dy + dh) > disph {
dhd = (dy + dh) - disph
shd = dhd * sh / dh
sh -= shd
dh -= dhd
}
; gzoom は透明色を扱えないので小技が必要
; 一旦、仮バッファに拡大縮小描画
gsel tmpid
pos 0, 0
gzoom dw, dh, srcid, sx, sy, sw, sh, 0
; 仮バッファから実スクリーンに gcopy でコピー
; gcopy なら RGB=(0,0,0) を透明色として扱える
gsel dstid
gmode gmode_rgb0 ; RGB=(0,0,0)を透明色として扱う
pos dx, dy
gcopy tmpid, 0, 0, dw, dh
; draw text
if 0 {
gmode gmode_gdi
font "Arial", 18, 1
color 255, 255, 255
pos 4, 80
mes "x, y = " + dstx + ", " + dsty
pos 4, 100
mes "dst x, y, w, h = " + dx + ", " + dy + " ," + dw + " ," + dh
pos 4, 120
mes "src x, y, w, h = " + sx + ", " + sy + " ," + sw + " ," + sh
}
return
#global
*jobend
end
使用画像は以下。
_bg_bg0.png
_bg_bg1.png
動作結果は以下。
今気づいたけど、奥側のBGレイヤーについては、RGB=(0,0,0) を透明色として扱う gmode gmode_rgb0 を使わずに、ベタ転送する gmode gmode_gdi を使ったほうが良かったのでは…? そうすれば、少しは処理時間が短くなったのでは…。いや、焼け石に水か…。
これまた今気づいたけど、手前側のBGレイヤーの下半分で、奥側のBGレイヤーは完全に隠されてしまうのだから、そこは奥側を描画しなくても良かったのでは…? そうすれば、少しは処理時間が短くなったのでは…。まあ、それも焼け石に水かな…。
考えてみたら、BGが1枚しかなくても、ラスタースクロール相当をすれば多重スクロールに見えるよな…。縦方向に多重スクロールさせないなら、それで十分かも。まあ、そういう画像を作らないといかんのだけど。
[ ツッコむ ]
#2 [nitijyou] 近所の池が埋め立てられることになった
自宅近くの池が埋め立てられることになったようで、池の水が抜かれ始めていた。もう1/3ぐらいの水の量になっている。
子供の頃にフナ釣りをしていた池なので、消滅するのはなんだか残念。寂しいので、せめて写真ぐらいは残しておこうと、周囲を歩いてスマホで何枚か撮影。
撮影時に気づいたけれど、色んな鳥が池を住処にしていたようで。体が真っ青な奇麗な小鳥が枝にとまっていたり。翼を広げると1m以上ある大きな鳥が泥の上をひょこひょこと歩いていたり。そういえば昨日の夕方は、おそらく鴨が数十羽ほど池に浮かんでいたっけ。彼等はこれから別の住処を探さないといけないのだな…。
それにしても、この手の池の埋め立て云々は、一体誰が決めているのだろう。まあ、鳥達と違って人間にとっては、今となっては利用価値も少ないだろうけど。昔はこのあたり一帯が田んぼだったから水を確保するために池が必要だったはずだけど、それらの田んぼは当の昔に埋め立てられて、アパートだのマンションだの、住宅だのコンビニだのがずらりと建ってるし。阿武隈川が洪水になったら水が上がってくる場所なのに、ガンガン建てちゃって…。実際数年前にそのあたり浸水してた気がするけど…。
大雨が降った時、一気に下まで水が流れて行かないよう、この池はバッファの役目も果たしていたのではないかと思えるのだよな…。犬の散歩で池の周囲を歩いた際、周囲の丘や坂から集まってきた雨水が轟音を立てて池に噴射されてる様子を何度も目にしているし。プチ・ダム放流。みたいな。あの水量が、これからは一気に下の住宅地に流れていくのだなあ…。いや、今回埋め立てられるのは上池で、まだ下池が一応残っているから、直接住宅地まで流れるわけではないのだな。もっとも、下池は道路を作った時に、1/3〜1/4まで小さくされてしまったし。あの水量を、小さくなった下池だけで受け止められるものかな…。さて、どうなることやら。
子供の頃にフナ釣りをしていた池なので、消滅するのはなんだか残念。寂しいので、せめて写真ぐらいは残しておこうと、周囲を歩いてスマホで何枚か撮影。
撮影時に気づいたけれど、色んな鳥が池を住処にしていたようで。体が真っ青な奇麗な小鳥が枝にとまっていたり。翼を広げると1m以上ある大きな鳥が泥の上をひょこひょこと歩いていたり。そういえば昨日の夕方は、おそらく鴨が数十羽ほど池に浮かんでいたっけ。彼等はこれから別の住処を探さないといけないのだな…。
それにしても、この手の池の埋め立て云々は、一体誰が決めているのだろう。まあ、鳥達と違って人間にとっては、今となっては利用価値も少ないだろうけど。昔はこのあたり一帯が田んぼだったから水を確保するために池が必要だったはずだけど、それらの田んぼは当の昔に埋め立てられて、アパートだのマンションだの、住宅だのコンビニだのがずらりと建ってるし。阿武隈川が洪水になったら水が上がってくる場所なのに、ガンガン建てちゃって…。実際数年前にそのあたり浸水してた気がするけど…。
大雨が降った時、一気に下まで水が流れて行かないよう、この池はバッファの役目も果たしていたのではないかと思えるのだよな…。犬の散歩で池の周囲を歩いた際、周囲の丘や坂から集まってきた雨水が轟音を立てて池に噴射されてる様子を何度も目にしているし。プチ・ダム放流。みたいな。あの水量が、これからは一気に下の住宅地に流れていくのだなあ…。いや、今回埋め立てられるのは上池で、まだ下池が一応残っているから、直接住宅地まで流れるわけではないのだな。もっとも、下池は道路を作った時に、1/3〜1/4まで小さくされてしまったし。あの水量を、小さくなった下池だけで受け止められるものかな…。さて、どうなることやら。
◎ 2023/09/14追記 :
[ ツッコむ ]
以上、1 日分です。

