; 疑似3D道路を描画する / Drawing pseudo 3D roads
; 坂道を実装してみる
;
; Up, Down key : アクセル,ブレーキ
; Left, Right key: 横移動
; Z key : 仮想画面の解像度変更
; X key : フレームレート変更
;
; 2023/09/10 by mieki256
#include "hspmath.as"
; フレームレート
dim framerate_list, 7
framerate_list(0) = 30
framerate_list(1) = 50
framerate_list(2) = 60
framerate_list(3) = 10
framerate_list(4) = 15
framerate_list(5) = 20
framerate_list(6) = 25
; 仮想画面解像度
dim vscr_size, 6, 2
vscr_size(0, 0) = 640
vscr_size(0, 1) = 360
vscr_size(1, 0) = 800
vscr_size(1, 1) = 450
vscr_size(2, 0) = 1280
vscr_size(2, 1) = 720
vscr_size(3, 0) = 320
vscr_size(3, 1) = 180
vscr_size(4, 0) = 480
vscr_size(4, 1) = 270
vscr_size(5, 0) = 512
vscr_size(5, 1) = 288
; vscr_size(6, 0) = 1920
; vscr_size(6, 1) = 1080
VSCR_W_MAX = 1920
VSCR_H_MAX = 1080
; 実画面解像度
#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 BG0_FILE "bg_bg0.png"
#define BG1_FILE "bg_bg1.png"
#define SPR_FILE "trees.png"
; セグメントの区切りを色分け. 0 or 1 or 2
#define SEG_DELIMITER 0
; 同梱ファイル / bundled files
#pack BG0_FILE
#pack BG1_FILE
#pack SPR_FILE
#packopt name "road05" ; exe filename
#packopt type 0 ; generate ".exe"
#packopt xsize SCR_W
#packopt ysize SCR_H
; #define global ctype max(%1,%2) ((%1)*((%1)>=(%2))+(%2)*((%1)<(%2)))
; #define global ctype min(%1,%2) ((%1)*((%1)<=(%2))+(%2)*((%1)>(%2)))
; onkey goto *jobend
randomize 0
; get windows size
screen 0, SCR_W, SCR_H, 0
gsel 0
; width SCR_W, SCR_H
screen_w = ginfo_winx
screen_h = ginfo_winy
cls 4
; init virtual screen
vscrbufid = 1
buffer vscrbufid, VSCR_W_MAX, VSCR_H_MAX
vscr_size_idx = 0
dispw = vscr_size(vscr_size_idx, 0)
disph = vscr_size(vscr_size_idx, 1)
; load bg image
bgimgid0 = 4
buffer bgimgid0, 1280, 720
picload BG0_FILE
bg0w = ginfo_winx
bg0h = ginfo_winy
bgimgid1 = 5
buffer bgimgid1, 1280, 720
picload BG1_FILE
bg1w = ginfo_winx
bg1h = ginfo_winy
; load spite image
sprimgid0 = 6
buffer sprimgid0, 1024, 512
picload SPR_FILE
spr0w = ginfo_winx
spr0h = ginfo_winy
; init temporary image buffer
tmpid = 7
buffer tmpid, 4096, 4096
; 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
; セグメント作成用データ初期化用マクロ
#define set_array(%1, %2, %3, %4, %5, %6) \
%1(%2, 0) = %3 :\
%1(%2, 1) = %4 :\
%1(%2, 2) = %5 :\
%1(%2, 3) = %6 :
; セグメント作成用データ
; set_array 配列変数名, index, count, curve, pitch, billboard
; curve と pitch は100倍した値。
; HSPは int と double を配列内で混在できないらしいので…
dim segm, 25, 4
set_array segm, 0, 25, 0, 0, 0
set_array segm, 1, 28, 0, 0, BB_BEAM
set_array segm, 2, 30, 0, 0, BB_GRASS
set_array segm, 3, 20, 0, 0, BB_ARROWL
set_array segm, 4, 80, 200, 0, BB_TREE
set_array segm, 5, 10, 0, 0, BB_TREE
set_array segm, 6, 80, 0, -50, BB_GRASS
set_array segm, 7, 20, 0, 0, BB_ARROWR
set_array segm, 8, 10, -100, 0, BB_GRASS
set_array segm, 9, 50, -400, 0, BB_TREE
set_array segm, 10, 20, 0, 0, 0
set_array segm, 11, 50, 0, 100, BB_GRASS
set_array segm, 12, 40, 0, -100, BB_TREE
set_array segm, 13, 60, -50, 0, BB_TREE
set_array segm, 14, 50, 0, 0, BB_GRASS
set_array segm, 15, 20, 0, 0, BB_ARROWL
set_array segm, 16, 20, 200, 0, 0
set_array segm, 17, 30, 0, 0, BB_GRASS
set_array segm, 18, 40, -80, -80, BB_TREE
set_array segm, 19, 20, 0, 80, 0
set_array segm, 20, 20, 0, 0, BB_GRASS
set_array segm, 21, 40, 20, -60, BB_TREE
set_array segm, 22, 20, 0, 60, BB_GRASS
set_array segm, 23, 50, 0, 0, BB_GRASS
set_array 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
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
; 画面に描画するセグメントの個数
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))
; logmes "dist=" + dist
; dist = 200.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
; py = 0.0
ppx = 0.0
angle = 0.0
framerate_idx = 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, 255
; 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
; px += ((double(road_x) * 0.6) * sin(deg2rad(angle)))
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のスクロール量を変更
bg_x += curve * spd * 0.5
if spd > 0.0 {
if pitch == 0.0 {
d = spd * 0.75
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
}
} else {
d = spd * 0.5
bg_y += pitch * d
}
}
; 道路を描画するためのデータを計算
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
; 描画開始 / draw start
redraw 0
; gsel 0
gsel vscrbufid
; 背景(遠景)を描画 / draw BG
if SEG_DELIMITER <= 1 {
bgy = (bg1h / 2) - (disph / 2) + bg_y
if bgy < 0 : bgy = 0
if bgy >= (bg1h - disph) : bgy = bg1h - disph
bgw = bg1w
bgh = bg1h
bgx = int(double(bg_x) * 0.6) \ bgw
bgid = bgimgid1
gmode gmode_gdi
gosub *draw_bg
bgw = bg0w
bgh = bg0h
bgx = int(double(bg_x) * 0.8) \ bgw
bgid = bgimgid0
gmode gmode_rgb0
gosub *draw_bg
} else {
gmode gmode_gdi
color 0, 0, 0
boxf 0, 0, dispw, disph
}
gmode gmode_gdi
; 道路を描画 / draw road
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 < (dist / 4) : 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
; 仮想画面を実画面に転送
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
color 1, 1, 1
; pos 8, 4
; mes "Press cursor key"
msg = "Res:" + dispw + "x" + disph
msg += " " + int(nowframerate) + "fps"
msg += " bg_y = " + int(bg_y)
pos (SCR_W / 2) - 100, 2
mes msg
}
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
*draw_bg
; BGを1枚描画 / draw BG. 1 layer
; bgid : bg image buffer id
; bgx, bgy : bg position
; bgw, bgh : bg image width, height
; dispw, disph : screen width, height
if bgx >= 0 & bgx < (bgw - dispw) {
pos 0,0
gcopy bgid, bgx, bgy, dispw, disph
} else {
if bgx < 0 {
w = -bgx
pos 0, 0
gcopy bgid, bgw - w, bgy, w, disph
pos w, 0
gcopy bgid, 0, bgy, dispw - w, disph
} else {
w = bgw - bgx
pos 0, 0
gcopy bgid, bgx, bgy, w, disph
pos (bgw - bgx), 0
gcopy bgid, 0, bgy, dispw - w, disph
}
}
return
*get_easing_value
; イージングを考慮した値を返す
; easing : 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
imgid = sprimgid0
imgw = spr0w
imgh = spr0h
switch spr_kind
case 1
case 2
case 3
case 4
; tree
n = spr_kind - 1
z = double(z1)
spr_h = 450.0
scale = spr_scale * spr_h * double(dist) / z
dst_w = int(scale)
dst_h = int(scale)
spr_xpos = (double(spr_x) * double(dist) / z) + cx1
dst_x = int(spr_xpos - (dst_w / 2) + (dispw / 2))
dst_y = int(y0 - dst_h + base_y)
swbreak
case 5
case 6
; arrow sign
n = spr_kind - 1
z = double(z1)
spr_h = 150.0
scale = spr_scale * spr_h * double(dist) / z
dst_w = int(scale)
dst_h = int(scale)
spr_xpos = (double(spr_x) * double(dist) / z) + cx1
dst_x = int(spr_xpos - (dst_w / 2) + (dispw / 2))
dst_y = int(y0 - dst_h + base_y)
swbreak
case 7
; grass
n = 6
z = double(z1)
spr_h = 200.0
scale = spr_scale * spr_h * double(dist) / z
dst_w = int(scale)
dst_h = int(scale)
spr_xpos = (double(spr_x) * double(dist) / z) + cx1
dst_x = int(spr_xpos - (dst_w / 2) + (dispw / 2))
dst_y = int(y0 - dst_h + base_y)
swbreak
case 8
; beam
n = 7
z = double(z1)
spr_h = 1080.0
scale = spr_scale * spr_h * double(dist) / z
dst_w = int(scale)
dst_h = int(scale)
spr_xpos = (double(spr_x) * double(dist) / z) + cx1
dst_x = int(spr_xpos - (dst_w / 2) + (dispw / 2))
dst_y = int(y0 - dst_h + base_y)
swbreak
swend
if SEG_DELIMITER == 0 {
if z < (dist / 2) : return
; gosub *draw_sprite_gzoom
draw_sprite_gzoom dst_x, dst_y, dst_w, dst_h, imgid, imgw, imgh, n, tmpid, dispw, disph, vscrbufid
}
return
#module
; *draw_sprite_gzoom
#deffunc draw_sprite_gzoom int dst_x, int dst_y, int dst_w, int dst_h, int imgid, int imgw, int imgh, int n, int tmpid, int dispw, int disph, int dstid
; スプライト相当を拡大縮小して描画
;
; dst_x, dst_y : 描画先の左上座標
; dst_w, dst_h : 描画先のサイズ
; imgid : 元画像バッファID
; imgw, imgh : 元画像サイズ
; n : スプライトNo.
; tmpid : 作業用イメージバッファID
; dispw, disph : 画面サイズ
; dstid : 描画先バッファID
; テクスチャのソース座標を算出
src_w = (imgw / 4)
src_h = (imgh / 2)
src_x = (n & 3) * src_w
src_y = ((n >> 2) & 1) * src_h
if dst_x >= dispw or (dst_x + dst_w) < 0 : return
if dst_y >= disph or (dst_y + dst_h) < 0 : return
dx = dst_x
dy = dst_y
dw = dst_w
dh = dst_h
sx = src_x
sy = src_y
sw = src_w
sh = src_h
if dx < 0 {
; assert
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, imgid, 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
return
#global
*jobend
end
Last modified (2015/11/30)
v1.3 : bug fixed