; 疑似3D道路を描画する / Drawing pseudo 3D roads
; 仮想画面解像度が変更されても遠景の見た目が同じになるようにした
;
; Up, Down key : アクセル,ブレーキ
; Left, Right key: 横移動
; Z key : 仮想画面の解像度変更
; X key : フレームレート変更
;
; 2023/09/14 by mieki256
#include "hspmath.as"
; 実画面解像度
; 16:9
; #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 1920
; #define SCR_H 1080
; 4:3
; #define SCR_W 640
; #define SCR_H 480
; #define SCR_W 800
; #define SCR_H 600
; #define SCR_W 1024
; #define SCR_H 768
; #define SCR_W 1200
; #define SCR_H 900
; フレームレート
dim framerate_list, 7
framerate_list(0) = 10
framerate_list(1) = 15
framerate_list(2) = 20
framerate_list(3) = 25
framerate_list(4) = 30
framerate_list(5) = 50
framerate_list(6) = 60
framerate_idx = 4
; 配列初期化用マクロ
#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, 320, 180
set_array_n2 vscr_size, 1, 480, 270
set_array_n2 vscr_size, 2, 512, 288
set_array_n2 vscr_size, 3, 640, 360
set_array_n2 vscr_size, 4, 800, 450
set_array_n2 vscr_size, 5, 1280, 720
; set_array_n2 vscr_size, 6, 1920, 1080
vscr_size_idx = 3
VSCR_W_MAX = 1920
VSCR_H_MAX = 1080
; セグメントの区切りを色分け. 0 or 1 or 2
#define SEG_DELIMITER 0
; 同梱ファイル / bundled files
#define SPR_FILE "trees.png"
; #define BG0_FILE "bg_2560x1440.png"
#define BG0_FILE "bg_2560x1440.jpg"
#pack SPR_FILE
#pack BG0_FILE
#packopt name "road07" ; exe filename
#packopt type 0 ; generate ".exe"
#packopt xsize SCR_W
#packopt ysize SCR_H
randomize 0
; 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)
; init temporary image buffer
tmpid = 4
buffer tmpid, 4096, 4096
; load spite image
sprimgid0 = 5
buffer sprimgid0, 2048, 2048
picload SPR_FILE
spr0w = ginfo_winx
spr0h = ginfo_winy
; load bg image and scaling
gosub *init_bg
; 2次元配列初期化用マクロ
#define set_array_n4(%1, %2, %3, %4, %5, %6) \
%1(%2, 0) = %3 :\
%1(%2, 1) = %4 :\
%1(%2, 2) = %5 :\
%1(%2, 3) = %6 :
; texture table
; set_array_n4 配列変数名, index, x, y, w, h
dim tex_pos, 8, 4
set_array_n4 tex_pos, 0, 0, 0, 512, 512
set_array_n4 tex_pos, 1, 512, 0, 512, 512
set_array_n4 tex_pos, 2, 1024, 0, 512, 512
set_array_n4 tex_pos, 3, 1536, 0, 512, 512
set_array_n4 tex_pos, 4, 0, 512, 512, 512
set_array_n4 tex_pos, 5, 512, 512, 512, 512
set_array_n4 tex_pos, 6, 0, 1024, 512, 128
set_array_n4 tex_pos, 7, 1024, 512, 1024, 512
; init road y, width
road_y = 100 ; 道路のy位置
road_x = 300 ; 道路の幅(片側の幅)
; ビルボード(billboard) 種類定義
#define BB_TREE 1
#define BB_ARROWR 2
#define BB_ARROWL 3
#define BB_GRASS 4
#define BB_BEAM 5
; セグメント作成用データ
; set_array_n4 配列変数名, index, count, curve, pitch, billboard
; curve と pitch は100倍した値。
; HSPは int と double を配列内で混在できないらしいので…
dim segm, 25, 4
set_array_n4 segm, 0, 25, 0, 0, 0
set_array_n4 segm, 1, 28, 0, 0, BB_BEAM
set_array_n4 segm, 2, 30, 0, 0, BB_GRASS
set_array_n4 segm, 3, 20, 0, 0, BB_ARROWL
set_array_n4 segm, 4, 80, 200, 0, BB_TREE
set_array_n4 segm, 5, 10, 0, 0, BB_TREE
set_array_n4 segm, 6, 80, 0, -50, BB_GRASS
set_array_n4 segm, 7, 20, 0, 0, BB_ARROWR
set_array_n4 segm, 8, 10, -100, 0, BB_GRASS
set_array_n4 segm, 9, 50, -400, 0, BB_TREE
set_array_n4 segm, 10, 20, 0, 0, 0
set_array_n4 segm, 11, 50, 0, 100, BB_GRASS
set_array_n4 segm, 12, 40, 0, -100, BB_TREE
set_array_n4 segm, 13, 60, -50, 0, BB_TREE
set_array_n4 segm, 14, 50, 0, 0, BB_GRASS
set_array_n4 segm, 15, 20, 0, 0, BB_ARROWL
set_array_n4 segm, 16, 20, 200, 0, 0
set_array_n4 segm, 17, 30, 0, 0, BB_GRASS
set_array_n4 segm, 18, 40, -80, -80, BB_TREE
set_array_n4 segm, 19, 20, 0, 80, 0
set_array_n4 segm, 20, 20, 0, 0, BB_GRASS
set_array_n4 segm, 21, 40, 20, -60, BB_TREE
set_array_n4 segm, 22, 20, 0, 60, BB_GRASS
set_array_n4 segm, 23, 50, 0, 0, BB_GRASS
set_array_n4 segm, 24, 50, 0, 0, BB_TREE
; セグメント総数を取得
seg_max = 0
repeat length(segm)
seg_max += segm(cnt, 0)
loop
; セグメントのz幅を指定
seg_length = 20
seg_total_length = seg_length * seg_max
; 参照されるセグメントデータとして展開
dim seg, seg_max, 6
gosub *expand_segment
; 画面に描画するセグメントの個数
seg_distance = 160
; セグメントの画面上の位置を記録するバッファ
ddim seg_x0, seg_distance
ddim seg_y0, seg_distance
ddim seg_z0, seg_distance
ddim seg_cx0, seg_distance
; セグメントに付随するビルボード情報を記録するバッファ
dim seg_spr_kind, seg_distance
ddim seg_spr_x, seg_distance
ddim seg_spr_scale, seg_distance
; 画面までの距離 / distance to screen
#define FOV 120.0
dist = double(dispw / 2) / tan(deg2rad(FOV / 2))
#define SPR_Z_LIMIT (184.0 / 2.0)
camera_z = 0.0
spd = 0.0
xd = 0.0
yd = 0.0
zd = double(seg_length)
bg_x = 0.0
bg_y = 0.0
px = 0.0
ppx = 0.0
angle = 0.0
fps_change = 0
vscr_change = 0
gosub *set_framerate
*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_ESC+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)
dist = double(dispw / 2) / tan(deg2rad(FOV / 2))
}
} else {
vscr_change = 0
}
; フレームレート変更
if k & KEY_X {
if fps_change == 0 {
fps_change = 1
oldspdper = spd / spd_max
framerate_idx = (framerate_idx + 1) \ length(framerate_list)
gosub *set_framerate
spd = spd_max * oldspdper
}
} else {
fps_change = 0
}
gosub *set_framerate
; check cursor key
if k & KEY_UP {
spd += spda
if spd >= spd_max : spd = spd_max
}
if k & KEY_DOWN {
spd -= (spda * 3)
if spd < 0.0 : spd = 0.0
}
x_spd = (spd * 0.3)
if k & KEY_LEFT : ppx += x_spd
if k & KEY_RIGHT : ppx -= x_spd
px = ppx
angle += (spd * 0.05)
base_y = int(double(disph) * 0.5)
h = disph - base_y
; 最初のセグメント番号を取得
if camera_z = 0 {
seg_index = 0
} else {
; "\"はHSPの剰余記号。一般的なプログラミング言語なら "%" に相当
seg_index = (int(camera_z) / seg_length) \ seg_max
}
; カメラが居るセグメントのカーブ量とピッチ量を求める
curve = double(seg(seg_index, 1)) * 0.01
pitch = double(seg(seg_index, 2)) * 0.01
; カメラがセグメント内のどの位置に居るか割合を求める
z0 = seg(seg_index, 0)
z1 = z0 + seg_length
ccz = camera_z \ seg_total_length
camz = double(ccz - z0) / double(z1 - z0)
; セグメント内のカメラ位置に応じて事前に横方向にある程度ずらしておく
camang = camz * curve
xd = -camang
yd = -camz * pitch
zd = double(seg_length)
cx = -(xd * camz)
cy = -(yd * camz)
cz = 0.0
; BGのスクロール量を変更
gosub *calc_bg_pos
; 道路を描画するためのデータを計算
gosub *calc_road
; 描画開始 / draw start
redraw 0
gsel vscrbufid
; 背景(遠景)を描画 / draw BG
if SEG_DELIMITER <= 1 {
bgid = bgimgid(vscr_size_idx)
bw = bgw(vscr_size_idx)
bh = bgh(vscr_size_idx)
draw_bg vscrbufid, bg_x, bg_y, bgid, bw, bh, dispw, disph
} else {
gmode gmode_gdi
color 0, 0, 0
boxf 0, 0, dispw, disph
}
; 道路を描画 / draw road
gosub *draw_road
; 仮想画面を実画面に転送
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
color 1, 1, 1
objcolor 255, 255, 255
; pos 8, 4
; mes "Press cursor key"
pos (SCR_W / 2) - 80, 2
mes "Res:" + dispw + "x" + disph + " " + int(nowframerate) + "fps", 4
pos (SCR_W / 2) - 120, 22
mes "bg_x, bg_y = " + bg_x + ", " + bg_y, 4
}
redraw 1 ; 描画終了 / draw end
camera_z += spd
await (1000 / framerate_list(framerate_idx))
goto *mainloop
*set_framerate
nowframerate = double(framerate_list(framerate_idx))
spd_max = 960.0 / nowframerate
spda = spd_max / (nowframerate * 3.0)
if spd > spd_max : spd = spd_max
if spd < 0.0 : spd = 0.0
return
*draw_raster_road
; 道路を1ラスター分描画 / draw road 1 raster
; draw_x, draw_y : draw x, y
; road_w : road width
; kind : 0 or 1 or 2
; dispw : screen width
; draw ground
if kind = 0 {
; color R, G, B
color 114, 185, 66
} else {
color 22, 174, 63
}
; boxf x0, y0, x1, y1
boxf 0, draw_y, dispw, draw_y
; draw road base
switch kind
case 0
color 133, 149, 158
swbreak
case 1
color 149, 168, 179
swbreak
case 2
color 255, 0, 0
swbreak
swend
boxf draw_x, draw_y, draw_x + road_w, draw_y
; draw white line
lw = double(road_w) * 48.0 / 2048.0 ; white line width
switch kind
case 0
color 255, 255, 255
lx = double(draw_x)
boxf lx, draw_y, lx + lw, draw_y
lx = lx + road_w - lw
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + (double(road_w) * 0.5) - (lw * 0.5)
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + double(road_w) * 0.25 - (lw * 0.5)
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + double(road_w) * 0.75 - (lw * 0.5)
boxf lx, draw_y, lx + lw, draw_y
swbreak
case 1
color 228, 236, 252
lx = double(draw_x) + lw
boxf lx, draw_y, lx + lw, draw_y
lx = double(draw_x) + road_w - (lw * 2)
boxf lx, draw_y, lx + lw, draw_y
swbreak
swend
return
*get_easing_value
; イージングを考慮した値を返す
;
; easing : easing kind. 0 - 3
; v0 : value 0
; v1 : value 1
; per : percent. 0.0 - 1.0
; return ret_value
if 1 {
; HSP のイージング関数を使って処理
switch easing
case 0:
; not easing
ret_value = v0
swbreak
case 1:
; ease In
setease v0, v1, ease_quad_in
ret_value = int(geteasef(int(per * 4096), 4096))
swbreak
case 2:
; ease Out
setease v0, v1, ease_quad_out
ret_value = int(geteasef(int(per * 4096), 4096))
swbreak
case 3:
setease v0, v1, ease_quad_inout
ret_value = int(geteasef(int(per * 4096), 4096))
swbreak
swend
} else {
; 自前でイージング計算
v_diff = double(v1 - v0)
switch easing
case 0:
; not easing
ret_value = v0
swbreak
case 1:
; ease In
ret_value = v0 + int(v_diff * (per * per))
swbreak
case 2:
; ease Out
ret_value = v0 + int(v_diff * (1.0 - ((1.0 - per) * (1.0 - per))))
swbreak
case 3:
if per < 0.5 {
ret_value = v0 + int(v_diff * (2.0 * per * per))
} else {
vv = -2.0 * per + 2.0
ret_value = v0 + int(v_diff * (1.0 - ((vv * vv) / 2.0)))
}
swbreak
swend
}
return
*set_billboard
; 各セグメントに記録するビルボード情報を決める
;
; billboard : ビルボード種類
; road_x : 道路の幅(片側の幅)
; return spr_kind, spr_x, spr_scale
switch billboard
case 0
; none
spr_kind = 0
spr_x = 0
spr_scale = 0
swbreak
case BB_TREE
; tree
spr_kind = rnd(4) + 1
spr_x = rnd(400) + road_x + 100
if (rnd(2) & 1) == 0 : spr_x *= -1
spr_scale = 100 + rnd(100)
swbreak
case BB_ARROWR
case BB_ARROWL
; arrow sign right to left, left to right
if cnt \ 4 == 0 {
; arrow sign
spr_kind = 5 + (billboard - BB_ARROWR)
spr_x = road_x + 120
if billboard == 3 : spr_x *= -1
spr_scale = 100
} else {
; grass
spr_kind = 7
spr_x = rnd(50) + road_x + 120
if billboard == 3 : spr_x *= -1
spr_scale = 100
}
swbreak
case BB_GRASS
; grass
spr_kind = 7
spr_x = road_x + 200 + rnd(150)
if (rnd(2) & 1) == 0 : spr_x *= -1
spr_scale = 150 + rnd(50)
swbreak
case BB_BEAM
; beam
if cnt \ 7 = 0 {
; beam
spr_kind = 8
spr_x = 0
spr_scale = 100
} else {
; none
spr_kind = 0
spr_x = 0
spr_scale = 100
}
swbreak
swend
return
*draw_billboard
; draw billboard sprite
;
; spr_kind : kind. 0 = None, 1-4 = tree, 5-6 = sign
; spr_x : x position
; spr_scale : scale (double)
; z0, z1 : segment z value. segmnet[n] and segment[n+1]
; y0, y1 : segment y value. segmnet[n] and segment[n+1]
; cx0, cx1 : segment center x value. segmnet[n] and segment[n+1]
; dispw, disph : screen size
; dist : screen distance
if spr_kind <= 0 : return
switch spr_kind
case 1
case 2
case 3
case 4
; tree
n = spr_kind - 1
spr_w = 450.0
spr_h = 450.0
swbreak
case 5
case 6
; arrow sign
n = spr_kind - 1
spr_w = 200.0
spr_h = 200.0
swbreak
case 7
; grass
n = 6
spr_w = 200.0
spr_h = 50.0
swbreak
case 8
; beam
n = 7
spr_w = 1000.0
spr_h = 500.0
swbreak
swend
imgid = sprimgid0
imgw = spr0w
imgh = spr0h
z = double(z0)
y = y0
cx = cx0
scale = spr_scale * double(dist) / z
dst_w = int(spr_w * scale)
dst_h = int(spr_h * scale)
spr_xpos = (double(spr_x) * double(dist) / z) + cx
dst_x = int(spr_xpos - (dst_w / 2) + (dispw / 2))
dst_y = int(y - dst_h + base_y)
if SEG_DELIMITER == 0 {
if z < SPR_Z_LIMIT : return
; gosub *draw_sprite_gzoom
draw_sprite_gzoom vscrbufid, dst_x, dst_y, dst_w, dst_h, imgid, n, tmpid, dispw, disph, tex_pos
}
return
#module
#deffunc draw_sprite_gzoom int dstid, int dx, int dy, int dw, int dh, int srcid, int n, int tmpid, int dispw, int disph, array tex_pos
; スプライト相当を拡大縮小して描画
;
; dstid : 描画先バッファID
; dx, dy, dw, dh : 描画先左上座標、サイズ
; srcid : 元画像バッファID
; n : スプライトNo.
; tmpid : 作業用イメージバッファID
; dispw, disph : 画面サイズ
; tex_pos : テクスチャ座標テーブル
; テクスチャの x, y, w, h を取得
sx = tex_pos(n, 0)
sy = tex_pos(n, 1)
sw = tex_pos(n, 2)
sh = tex_pos(n, 3)
draw_by_gzoom dstid, dx, dy, dw, dh, srcid, sx, sy, sw, sh, tmpid, dispw, disph
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
*expand_segment
; 元になるセグメントデータから参照されるセグメントデータに展開
; dim seg, seg_max, 6
z = 0
i = 0
repeat length(segm)
n0 = cnt
n1 = (cnt + 1) \ length(segm)
lp = segm(n0, 0)
curve = segm(n0, 1)
pitch = segm(n0, 2)
billboard = segm(n0, 3)
next_curve = segm(n1, 1)
next_pitch = segm(n1, 2)
; イージング有効無効
#define EASING_ENABLE 0
if EASING_ENABLE {
; カーブ量やピッチ量をイージングで求める場合
if curve == next_curve {
curve_easing = 0
} else {
if curve == 0 {
curve_easing = 1 ; ease In
} else {
if next_curve == 0 {
curve_easing = 2 ; ease Out
} else {
curve_easing = 3 ; ease In Out
}
}
}
if pitch == next_pitch {
pitch_easing = 0
} else {
if pitch == 0 {
pitch_easing = 1 ; ease In
} else {
if next_pitch == 0 {
pitch_easing = 2 ; ease Out
} else {
pitch_easing = 3 ; ease In Out
}
}
}
}
repeat lp
seg(i, 0) = z
per = double(cnt) / double(lp)
if EASING_ENABLE {
; カーブ量やピッチ量をイージングで求める
v0 = curve
v1 = next_curve
easing = curve_easing
gosub *get_easing_value
seg(i, 1) = ret_value
v0 = pitch
v1 = next_pitch
easing = pitch_easing
gosub *get_easing_value
seg(i, 2) = ret_value
} else {
; カーブ量やピッチ量を線形補完で求める
seg(i, 1) = curve + int(double(next_curve - curve) * per)
seg(i, 2) = pitch + int(double(next_pitch - pitch) * per)
}
; set billboard sprite
gosub *set_billboard
seg(i, 3) = spr_kind
seg(i, 4) = spr_x
seg(i, 5) = spr_scale
z += seg_length
i++
loop
loop
return
*calc_road
; 道路を描画するための座標値を計算して記録
i = 0
seg_z_max = 0
repeat (seg_distance + 1)
; セグメントのz値、カーブ量、ピッチ量を取得
idx = (seg_index + cnt) \ seg_max
z0 = seg(idx, 0)
curve = double(seg(idx, 1)) * 0.01
pitch = double(seg(idx, 2)) * 0.01
; 最後のセグメントを超えて最初にループする場合、z値を調整する
if z0 > seg_z_max : seg_z_max = z0
if z0 < seg_z_max : z0 += seg_total_length
cam_z = int(camera_z) \ seg_total_length
z0 -= cam_z
if z0 = 0 : z0 = 1 ; 0で除算しないように微調整
; 画面上で描画すべきy座標位置を取得
y0 = (double(road_y) + cy) * dist / double(z0)
; 画面上で描画すべき道路の幅(片側の幅)を取得
x0 = double(road_x) * double(dist) / double(z0)
; 画面上でずらすべき中心線の位置を取得
cx0 = (double(cx) + px) * double(dist) / double(z0)
; 描画用に記録
seg_z0(i) = double(z0)
seg_y0(i) = double(y0)
seg_x0(i) = double(x0)
seg_cx0(i) = double(cx0)
; スプライト相当の情報も記録
seg_spr_kind(i) = seg(idx, 3)
seg_spr_x(i) = double(seg(idx, 4))
seg_spr_scale(i) = double(seg(idx, 5)) * 0.01
cx += xd
cy += yd
cz += zd
xd += curve
yd += pitch
i++
loop
return
*draw_road
; 道路を描画
gmode gmode_gdi
repeat seg_distance
i = seg_distance - cnt - 1
i1 = seg_distance - cnt
x0 = seg_x0(i)
y0 = seg_y0(i)
z0 = seg_z0(i)
cx0 = seg_cx0(i)
x1 = seg_x0(i1)
y1 = seg_y0(i1)
z1 = seg_z0(i1)
cx1 = seg_cx0(i1)
spr_kind = seg_spr_kind(i)
spr_x = seg_spr_x(i)
spr_scale = seg_spr_scale(i)
if z1 < (SPR_Z_LIMIT / 2) : goto *seg_draw_cancel
; 各セグメントが作る台形を塗り潰す
if SEG_DELIMITER <= 1 {
; y0 < y1 なら道路の裏面を見てる。描画をスキップ
if y0 < y1 : goto *seg_draw_cancel
h = abs(y1 - y0) + 1
dsy = sgn(y1 - y0)
if dsy = 0 : dsy = 1
repeat h
sy = y0 + (dsy * cnt)
draw_y = sy + base_y
; 画面縦幅を超えたy座標なら描画しない
if draw_y < 0 | draw_y > disph : continue
; 2次元的な計算で割合を求める
if y0 == y1 {
p = 0.0
} else {
p = double(sy - y0) / double(y1 - y0)
}
z = (double(z1) - double(z0)) * p + double(z0)
x = (double(x1) - double(x0)) * p + double(x0)
center_x = (cx1 - cx0) * p + cx0
addv = ((int(z) + int(camera_z)) / 40) & $1
; 1ラスター分を描画 / draw 1 raster
road_w = x * 2
draw_x = -x + center_x + (dispw / 2)
kind = addv
if SEG_DELIMITER = 1 {
; セグメントの区切りを色分けしたい場合
if sy = y0 : kind = 2
}
gmode gmode_gdi
gosub *draw_raster_road
loop
} else {
; デバッグ用。セグメントの区切り線だけを描画
d = (dispw / 2)
color 255, 0, 0
line cx0 + x0 + d, y0 + base_y, cx0 - x0 + d, y0 + base_y
if 0 {
line cx1 - x1 + d, y1 + base_y, cx0 - x0 + d, y0 + base_y
line cx1 + x1 + d, y1 + base_y, cx0 + x0 + d, y0 + base_y
}
color 255, 255, 0
line cx1 + d, y1 + base_y, cx0 + d, y0 + base_y
}
*seg_draw_cancel
; draw billboard sprite
if spr_kind <= 0 : continue
gosub *draw_billboard
loop
return
*init_bg
; load bg
k = length(vscr_size)
dim bgimgid, k
dim bgw, k
dim bgh, k
i = k - 1
bgimgid(i) = 6 + i
buffer bgimgid(i), 2560, 1440
picload BG0_FILE
bgw(i) = ginfo_winx
bgh(i) = ginfo_winy
; scaling
repeat k - 1
bgw(cnt) = vscr_size(cnt, 0) * 2
bgh(cnt) = vscr_size(cnt, 1) * 2
bgimgid(cnt) = 6 + cnt
buffer bgimgid(cnt), bgw(cnt), bgh(cnt)
gsel bgimgid(cnt)
gzoom bgw(cnt), bgh(cnt), bgimgid(i), 0, 0, bgw(i), bgh(i), 1
loop
return
*calc_bg_pos
; BGスクロール位置を計算
; curve, pitch
; spd, spd_max
; bg_x, bg_y
fper = 30.0 / nowframerate
bg_x += curve * (spd / spd_max) * 0.1 * fper
if spd > 0.0 {
if pitch != 0.0 {
bg_y += pitch * (spd / spd_max) * 0.1 * fper
} else {
d = (spd / spd_max) * 0.2 * fper
if bg_y < 0.0 {
bg_y += (d * 0.1)
if bg_y >= 0.0 : bg_y = 0.0
}
if bg_y > 0.0 {
bg_y -= (d * 0.1)
if bg_y <= 0.0 : bg_y = 0.0
}
}
; bg_y += ((pitch * 2.0) - bg_y) * 0.15
if bg_y < -1.0 : bg_y = -1.0
if bg_y > 1.0 : bg_y = 1.0
}
return
#module
#deffunc draw_bg int dstid, double bg_x, double bg_y, int bgimgid, int bgw, int bgh, int dispw, int disph
; 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
bx = bg_x
by = bg_y
if by < -1.0 : by = -1.0
if by > 1.0 : by = 1.0
bgid = bgimgid
bw = bgw
bh = bgh
shiftx = bx
sx = int(double(bh / 4) * bx) \ bw
sy = int(double(bh / 4) * by) + (bh / 2) - (bh / 4)
sw = dispw
sh = disph
gsel dstid
gmode gmode_gdi
if sx >= 0 and (sx + dispw) < bw {
pos 0, 0
gcopy bgid, sx, sy, dispw, disph
} else {
if (sx + dispw) > bw : sx = (sx - bw) \ bw
w = -sx
sw0 = w
sx0 = bw - w
pos 0, 0
gcopy bgid, sx0, sy, sw0, sh
sw1 = sw - w
sx1 = 0
pos sw0, 0
gcopy bgid, sx1, sy, sw1, sh
}
return
#global
*jobend
end
Last modified (2015/11/30)
v1.3 : bug fixed