(module (import "console" "log" (func $log (param i32))) (import "js" "mem" (memory $mem 1)) # n回の呼び出し毎にデバッグ値を出力する (global $dbgcnt (mut i32) i32.push 0 ) (func $dbgval (param $val i32) global.push dbgcnt i32.push 0x3F i32.and if else # dbgcnt & 0x3F == 0 push val call log end global.push dbgcnt i32.push 1 i32.add global.pop dbgcnt ) # 回転(拡大縮小)機能 (func (export "rotnscl") (param $v i32) (param $w i32) (local $it i32) (local $rx16 i32) # rxy: サンプリングxy開始点計算用 (local $ry16 i32) (local $hx16 i32) # hxy: 水平方向サンプリングxy間隔 (local $hy16 i32) (local $vx16 i32) # vxy: 垂直方向サンプリングxy間隔 (local $vy16 i32) (local $dest_adr i32) (local $w16 i32) (local $x i32) (local $_vx16 i32) (local $_vy16 i32) (local $_hx16 i32) (local $_hy16 i32) # テーブルから cos, sin を得る 0x200000 - 0x2007FF: table (cos:4 sin:4) x 256 push v i32.push 3 i32.shl # [ (v << 3) pop_push it push it push it # [ (v << 3) (v << 3) (v << 3) # rxy: サンプリングxy開始点計算用 i32.push 0x200400 # 0x200000 + PI:128 << 3 i32.add # [ (v << 3) (v << 3) ((v << 3) + (PI << 3)) i32.push 0x2007F8 i32.and # [ (v << 3) (v << 3) *cos(v + 128) pop_push it push it i32.push 4 i32.add # [ (v << 3) (v << 3) *cos(v + 128) *sin(v + 128) i32.load pop ry16 # ry16 = sin(v + 128) <16bit.16bit> i32.load pop rx16 # rx16 = cos(v + 128) <16bit.16bit> # hxy: 水平方向サンプリングxy間隔 i32.push 0x200000 # 0x200000 i32.add # [ (v << 3) (v << 3) i32.push 0x2007F8 i32.and # [ (v << 3) *cos(v) pop_push it push it i32.push 4 i32.add # [ (v << 3) *cos(v) *sin(v) i32.load pop hy16 # hy16 = sin(v) <16bit.16bit> i32.load pop hx16 # hx16 = cos(v) <16bit.16bit> # vxy: 垂直方向サンプリングxy間隔 i32.push 0x200200 # 0x200000 + (PI/2):64 << 3 i32.add # [ (v << 3) ((v << 3) + ((PI/2) << 3)) i32.push 0x2007F8 i32.and # [ (v << 3) *cos(v + 64) pop_push it push it i32.push 4 i32.add # [ *cos(v + 64) *sin(v + 64) i32.load pop vy16 # vy16 = sin(v + 64) <16bit.16bit> i32.load pop vx16 # vx16 = cos(v + 64) <16bit.16bit> # 描画先アドレス push w push w i32.mul i32.push 2 i32.shl pop dest_adr # dest_adr = (w * w) << 2 # _vx16, _vy16: サンプリングxy開始点 push w i32.push 1 i32.shr_u pop_push it # [ (dxy = w >> 1) push it # [ dxy dxy i32.push 65536 push rx16 push ry16 # [ dxy dxy 65536 rx16 ry16 i32.sub i32.add i32.mul # [ dxy dxy * (65536 + rx16 - ry16) pop _vx16 # _vx16 = (dxy * rx16) - (dxy * ry16) + (dxy << 16) <16bit.16bit> i32.push 65536 push ry16 push rx16 # [ dxy 65536 ry16 rx16 i32.add i32.add i32.mul # [ dxy * (65536 + ry16 + rx16) pop _vy16 # _vy16 = (dxy * ry16) + (dxy * rx16) + (dxy << 16) <16bit.16bit> # サンプリング範囲外チェック用に w16 を作っておく push w i32.push 16 i32.shl pop w16 # w16 = w << 16 vloop: loop # 垂直方向ループ # 水平方向カウンタを初期化 push w pop x # x = w # サンプリング位置を垂直方向に進め、水平方向の初期位置としてセット push _vx16 push vx16 i32.add pop_push _vx16 # _vx16 += vx16 pop _hx16 # _hx16 = _vx16 push _vy16 push vy16 i32.add pop_push _vy16 # _vy16 += vy16 pop _hy16 # _hy16 = _vy16 hloop: loop # 水平方向ループ push dest_adr i32.push 4 i32.sub pop_push dest_adr # [ (dest_adr -= 4) sblock: block (result i32) # [ dest_adr # 透過色を持つアドレス i32.push 0x200800 # [ dest_adr 0x200800 # サンプリング位置を水平方向に進める push _hx16 push hx16 i32.add pop_push _hx16 # [ dest_adr 0x200800 (_hx16 += hx16) push _hy16 push hy16 i32.add pop_push _hy16 # [ dest_adr 0x200800 _hx16 (_hy16 += hy16) # サンプリング範囲外チェック i32.or # [ dest_adr 0x200800 (_hx16 | _hy16) push w16 i32.ge_u # [ dest_adr 0x200800 ((_hx16 | _hy16) >= (w << 16)) br_if sblock # [ dest_adr break(0x200800) # 透過色を持つアドレスを捨てる drop # [ dest_adr # サンプリングアドレス計算 i32.push 0x100000 # [ dest_adr 0x100000 push _hy16 i32.push 16 i32.shr_u push w i32.mul # [ dest_adr 0x100000 (_hy16 >> 16 * w) push _hx16 i32.push 16 i32.shr_u i32.add # [ dest_adr 0x100000 ((_hy16 >> 16 * w) + (_hx16 >> 16)) i32.push 2 i32.shl # [ dest_adr 0x100000 ((_hy16 >> 16 * w) + (_hx16 >> 16) << 2) i32.add # [ dest_adr src_adr end # sblock # サンプリング&描画 i32.load # [ dest_adr color i32.store # [ push x i32.push 1 i32.sub pop_push x jp_nz hloop # (x -= 1) != 0 and loop end push dest_adr jp_nz vloop # dest_adr != 0 and loop end ) ) __END__