mieki256's diary



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 のタイミングだったようで、そのあたりが影響してる気がする…。

テストプログラムを置いておく :

一応、2枚のBG画像を縮小描画しながらスクロールさせるテストプログラムを置いておく。

_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

動作結果は以下。

ss_bgscroll_ss01.gif

今気づいたけど、奥側のBGレイヤーについては、RGB=(0,0,0) を透明色として扱う gmode gmode_rgb0 を使わずに、ベタ転送する gmode gmode_gdi を使ったほうが良かったのでは…? そうすれば、少しは処理時間が短くなったのでは…。いや、焼け石に水か…。

これまた今気づいたけど、手前側のBGレイヤーの下半分で、奥側のBGレイヤーは完全に隠されてしまうのだから、そこは奥側を描画しなくても良かったのでは…? そうすれば、少しは処理時間が短くなったのでは…。まあ、それも焼け石に水かな…。

考えてみたら、BGが1枚しかなくても、ラスタースクロール相当をすれば多重スクロールに見えるよな…。縦方向に多重スクロールさせないなら、それで十分かも。まあ、そういう画像を作らないといかんのだけど。

以上です。

過去ログ表示

Prev - 2023/09 - 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

カテゴリで表示

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


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

Powered by hns-2.19.6, HyperNikkiSystem Project