#apply
#include "../_include.txt"
#include "../../define/_vector2.txt"

/*
@param
中心点x
y
移動後の中心点x
y
座標の単位
めり込み修正の単位
対象ピクチャID

@return
衝突時間 (-1:衝突なし)
中心点x
y
法線x
y
*/
cev[CEV_POINT_TO_COLLMAP] .name(">>>>動く点と衝突マップ") bl {
    defv {
        r_time = TV_RETURN
        r_cx
        r_cy
        r_nx
        r_ny

        a_sx = TV_POINT_TO_COLLMAP
        a_sy
        a_ex
        a_ey
        a_unit
        a_react
        a_pic

        pixel
        angle
        dist
        velo
        px
        py
        pw
        ph
        sx
        sy
        vx
        vy
        sgx
        sgy
        adx
        ady
        ax
        ay
        bx
        by
        cx
        cy//29
    }

    def {
        MAX_JUDGE = 16//pixel
        MAX_REACT  = 8//押し戻す回数
        UNIT_CHECK = 1000
        UNIT_ANGLE = 10
        UNIT_LOOP = (360 * UNIT_ANGLE)//一回転

        MASK_COLOR = 0xff
        MAX_WALL   = 0x90
        MIN_WALL   = 0xff - 0x90

        SHIFT_BLUE  = 0
        SHIFT_GREEN = 8
        SHIFT_RED   = 16
        SHIFT_ALPHA = 24
    }

    //返り値を初期化
    r_time = -1

    //ピクチャの位置を取得する
    @pic.getInfo [a_pic] .currentRect(px, py, pw, ph) .xywh

    //ピクチャの幅がない=ピクチャが存在しない
    @if pw <= 0 bl ABORT_BLOCK

    //移動中にピクチャ内に入るかもしれないので、簡易判定はない

    //マップを基準としたピクチャ座標を算出する
    @sys.getInfo .camera .dst(ax)
    V2_asAdd(px, ax)

    //プレゼンハムアルゴリズムを使って走査する
    //v:レイ s:始点 a:判定座標(unit) b:判定座標(px) c:現在の位置(unit)

    V2_sub(vx, a_ex, a_sx)
    V2_copy(sx, a_sx)
    V2_set(sgx, 1, 1)
    V2_set(adx, 0, 0)

    @if vx < 0 bl {
        sx *= -1
        vx *= -1
        sgx = -1
        adx = a_unit

    }

    @if vy < 0 bl {
        sy *= -1
        vy *= -1
        sgy = -1
        ady = a_unit

    }

    //開始位置
    V2_math(bl { v[$c] = v[$sg] * (v[$st] + v[$ad]) },
        bl {
            $c  = $i + __id(cx)
            $st = $i + __id(a_sx)
            $sg = $i + __id(sgx)
            $ad = $i + __id(adx)
        }
    )

    @loop MAX_JUDGE bl {
        //判定する座標
        V2_math(bl { v[$a] = v[$sg] * (v[$c] + v[$ad]) },
            bl {
                $a  = $i + __id(ax)
                $c  = $i + __id(cx)
                $sg = $i + __id(sgx)
                $ad = $i + __id(adx)
            }
        )

        //色が有効かどうか
        $pixelCheck = ((pixel >> SHIFT_BLUE) & MASK_COLOR) >= MIN_WALL

        //ピクセルを取得する
        $getPixel = bl {
            //座標を変換する
            V2_math(bl { v[$b] = v[$a] / a_unit - v[$p] },
                bl {
                    $b = $i + __id(bx)
                    $a = $i + __id(ax)
                    $p = $i + __id(px)
                }
            )

            //範囲外だと代入されないが、稀にピクチャIDがゼロになってエラーが出るようだ
            //たまにメモリエラーも出る辺り、慎重に扱うべきかもしれない
            @if `bx < 0 || pw <= bx || by < 0 || ph <= by bl {
                pixel = 0

            } .else {
                @pic.getInfo [a_pic] .pixel(bx, by, 1, 1) .dst(pixel) .ignoreA .static

            }

        }

        //法線を更新する
        $updateNormal = bl {
            angle = lerp(0, UNIT_LOOP, ((pixel >> SHIFT_BLUE) & MASK_COLOR) - MIN_WALL, MAX_WALL)
            V2_getCosSin(r_nx, angle, UNIT_ANGLE, UNIT_NORMAL)

        }

        //ピクセルを取得する
        $getPixel

        @if `$pixelCheck bl {
            //法線
            $updateNormal

            //衝突後の座標
            //めり込みを修正する
            //法線方向にあるピクセルを見て、有効だった場合は移動し、有効でない場合は終了する
            //若干めり込んだ状態で終わらせたい
            V2_copy(r_cx, ax)

            @loop MAX_REACT bl {
                V2_asAddMuldiv(ax, r_nx, a_react, UNIT_NORMAL)

                $getPixel

                @if `$pixelCheck bl {
                    V2_copy(r_cx, ax)

                    $updateNormal

                } .else bl {
                    @break

                }

            }

            //衝突時間
            V2_dist(dist, r_cx, a_sx)
            V2_mag(velo, vx)

            //移動距離が単位未満の場合、衝突時間はゼロになる
            @if `velo <= a_unit || dist <= a_unit bl {
                r_time = 0

            //判定位置が先に行っている場合、衝突はなかったことになる
            } .elif velo < dist bl {
                r_time = -1

            //それ以外の場合、衝突時間は sqrt(判定位置-始点) / sqrt(終点-始点) * 時間単位 となる
            } .else {
                r_time = lerp(0, UNIT_SECOND, dist, velo)

            }

            //判定を終了する
            @break

        }

        //次の判定へ
        //a:係数
        V2_math(bl { v[$a] = v[$v] != 0 ? muldiv( v[$c] + a_unit - v[$s], UNIT_CHECK, v[$v] ) : (UNIT_CHECK + 1) },
            bl {
                $a = $i + __id(ax)
                $c = $i + __id(cx)
                $v = $i + __id(vx)
                $s = $i + __id(sx)
            }
        )

        //over
        @if `ax > UNIT_CHECK && ay > UNIT_CHECK bl {
            @break

        //x-side
        } .elif ax < ay bl {
            cx += a_unit

        //y-side
        } .elif ax > ay bl {
            cy += a_unit

        //corner
        } .else bl {
            cx += a_unit
            cy += a_unit

        }

    }

}