//
// Generated by dtk
// Translation Unit: c_m3d.cpp
//

#include "SSystem/SComponent/c_m3d.h"
#include "JSystem/JUtility/JUTAssert.h"
#include "SSystem/SComponent/c_m3d_g_aab.h"
#include "SSystem/SComponent/c_m3d_g_cps.h"
#include "SSystem/SComponent/c_m3d_g_cyl.h"
#include "SSystem/SComponent/c_m3d_g_lin.h"
#include "SSystem/SComponent/c_m3d_g_pla.h"
#include "SSystem/SComponent/c_m3d_g_sph.h"
#include "SSystem/SComponent/c_m3d_g_tri.h"
#include "SSystem/SComponent/c_math.h"
#include "SSystem/SComponent/c_sxyz.h"

#define CHECK_FLOAT_RANGE(line, x) JUT_ASSERT(line, -1.0e32f < x && x < 1.0e32f);
#define CHECK_VEC3_RANGE(line, v) JUT_ASSERT(line, -1.0e32f < v.x && v.x < 1.0e32f && -1.0e32f < v.y && v.y < 1.0e32f && -1.0e32f < v.z && v.z < 1.0e32f)
#define CHECK_PVEC3_RANGE(line, v) JUT_ASSERT(line, -1.0e32f < v->x && v->x < 1.0e32f && -1.0e32f < v->y && v->y < 1.0e32f && -1.0e32f < v->z && v->z < 1.0e32f)

const f32 G_CM3D_F_ABS_MIN = 3.8146973e-06f;
#if VERSION == VERSION_DEMO
const f32 G_CM3D_F_INF = 1.0e38f;
#endif

static void dummy(f32 dummy) {
    // to fix float literal order
    std::sqrtf(dummy);
}

/* 8024A400-8024A450       .text cM3d_InDivPos1__FPC3VecPC3VecfP3Vec */
void cM3d_InDivPos1(const Vec* v0, const Vec* v1, f32 scale, Vec* pDst) {
    Vec tmp;
    VECScale(v1, &tmp, scale);
    VECAdd(&tmp, v0, pDst);
}

/* 8024A450-8024A4B4       .text cM3d_InDivPos2__FPC3VecPC3VecfP3Vec */
void cM3d_InDivPos2(const Vec* v0, const Vec* v1, f32 scale, Vec* pDst) {
    Vec tmp;
    VECSubtract(v1, v0, &tmp);
    cM3d_InDivPos1(v0, &tmp, scale, pDst);
}

/* 8024A4B4-8024A56C       .text cM3d_Len2dSqPntAndSegLine__FffffffPfPfPf */
bool cM3d_Len2dSqPntAndSegLine(f32 xp, f32 yp, f32 x0, f32 y0, f32 x1, f32 y1, f32* outx, f32* outy, f32* seg) {
    bool ret = false;
    f32 xd = x1 - x0;
    f32 yd = y1 - y0;
    f32 dot = (xd * xd + yd * yd);
    if (cM3d_IsZero(dot)) {
        *seg = 0.0f;
        return false;
    }

    f32 mag = (xd * (xp - x0) + yd * (yp - y0)) / dot;
    if (mag >= 0.0f && mag <= 1.0f) {
        ret = true;
    }

    *outx = x0 + xd * mag;
    *outy = y0 + yd * mag;
    *seg = cM3d_Len2dSq(*outx, *outy, xp, yp);
    return ret;
}

/* 8024A56C-8024A670       .text cM3d_Len3dSqPntAndSegLine__FPC8cM3dGLinPC3VecP3VecPf */
bool cM3d_Len3dSqPntAndSegLine(const cM3dGLin* line, const Vec* pos, Vec* pDst, f32* pT) {
    Vec work2;
    Vec work1;

    VECSubtract(line->GetEndP(), line->GetStartP(), &work2);
    f32 midPoint = VECDotProduct(&work2, &work2);
    if ((cM3d_IsZero(midPoint))) {
        *pT = 0.0f;
        return false;
    }

    VECSubtract(pos, line->GetStartP(), &work1);
    midPoint = VECDotProduct(&work1, &work2) / midPoint;

    bool success;
    if (midPoint < 0.0f || midPoint > 1.0f) {
        success = false;
    } else {
        success = true;
    };

    VECScale(&work2, &work2, midPoint);
    VECAdd(&work2, line->GetStartP(), pDst);
    *pT = VECSquareDistance(pDst, pos);
    return success;
}

/* 8024A670-8024A6F0       .text cM3d_SignedLenPlaAndPos__FPC8cM3dGPlaPC3Vec */
f32 cM3d_SignedLenPlaAndPos(const cM3dGPla* plane, const Vec* pos) {
    f32 len = VECMag(plane->GetNP());
    if (cM3d_IsZero(len))
        return 0.0f;
    else
        return plane->getPlaneFunc(pos) / len;
}

/* 8024A6F0-8024A7BC       .text cM3d_CalcPla__FPC3VecPC3VecPC3VecP3VecPf */
void cM3d_CalcPla(const Vec* p0, const Vec* p1, const Vec* p2, Vec* pDst, f32* pT) {
    cM3d_VectorProduct(p0, p1, p2, pDst);
    f32 t = VECMag(pDst);
#if VERSION == VERSION_DEMO
    if (!cM3d_IsZero(t))
#else
    if (std::fabsf(t) >= 0.02f)
#endif
    {
        VECScale(pDst, pDst, 1.0f / t);
        *pT = -VECDotProduct(pDst, p0);
    } else {
        pDst->y = 0.0f;
        *pT = 0.0f;
        pDst->z = 0.0f;
        pDst->x = 0.0f;
    }
}

inline bool cM3d_CrossNumSection(f32 lMinX, f32 lMaxX, f32 rMinX, f32 rMaxX) {
    if (lMinX > rMaxX) {
        return false;
    } else if (lMaxX < rMinX) {
        return false;
    } else if (rMinX > lMaxX) {
        return false;
    } else if (rMaxX < lMinX) {
        return false;
    } else {
        return true;
    }
}

/* 8024A7BC-8024A8E0       .text cM3d_Cross_AabAab__FPC8cM3dGAabPC8cM3dGAab */
bool cM3d_Cross_AabAab(const cM3dGAab* a, const cM3dGAab* b) {
    if (cM3d_CrossNumSection(a->GetMinP()->x, a->GetMaxP()->x, b->GetMinP()->x, b->GetMaxP()->x) &&
        cM3d_CrossNumSection(a->GetMinP()->y, a->GetMaxP()->y, b->GetMinP()->y, b->GetMaxP()->y) &&
        cM3d_CrossNumSection(a->GetMinP()->z, a->GetMaxP()->z, b->GetMinP()->z, b->GetMaxP()->z)) {
        return true;
    } else {
        return false;
    }
}

/* 8024A8E0-8024A988       .text cM3d_Cross_AabCyl__FPC8cM3dGAabPC8cM3dGCyl */
bool cM3d_Cross_AabCyl(const cM3dGAab* aab, const cM3dGCyl* cyl) {
    if (aab->GetMinP()->x > cyl->GetCP()->x + cyl->GetR()) {
        return false;
    } else if (aab->GetMaxP()->x < cyl->GetCP()->x - cyl->GetR()) {
        return false;
    } else if (aab->GetMinP()->z > cyl->GetCP()->z + cyl->GetR()) {
        return false;
    } else if (aab->GetMaxP()->z < cyl->GetCP()->z - cyl->GetR()) {
        return false;
    } else if (aab->GetMinP()->y > cyl->GetCP()->y + cyl->GetH()) {
        return false;
    } else if (aab->GetMaxP()->y < cyl->GetCP()->y) {
        return false;
    } else {
        return true;
    }
}

/* 8024A988-8024AA30       .text cM3d_Cross_AabSph__FPC8cM3dGAabPC8cM3dGSph */
bool cM3d_Cross_AabSph(const cM3dGAab* aab, const cM3dGSph* sph) {
    f32 radius = sph->GetR();
    f32 cx = sph->GetC().x;
    if (aab->GetMinX() > cx + radius) {
        return false;
    }
    else if (aab->GetMaxX() < cx - radius) {
        return false;
    }

    f32 cz = sph->GetC().z;
    if (aab->GetMinZ() > cz + radius) {
        return false;
    } else if (aab->GetMaxZ() < cz - radius) {
        return false;
    }
    
    f32 cy = sph->GetC().y;
    if (aab->GetMinY() > cy + radius) {
        return false;
    } else if (aab->GetMaxY() < cy - radius) {
        return false;
    }
    return true;
}

/* 8024AA30-8024ACA8       .text cM3d_Check_LinLin__FPC8cM3dGLinPC8cM3dGLinPfPf */
int cM3d_Check_LinLin(const cM3dGLin* lin_a, const cM3dGLin* lin_b, f32* dst_a, f32* dst_b) {
    Vec linAVec;
    Vec linBVec;
    lin_a->CalcVec(&linAVec);
    lin_b->CalcVec(&linBVec);
    f32 linALen = VECMag(&linAVec);
    f32 linBLen = VECMag(&linBVec);
    if (cM3d_IsZero(linALen) || cM3d_IsZero(linBLen)) {
        return 1;
    } else {
        f32 invLinALen = 1.0f / linALen;
        f32 invLinBLen = 1.0f / linBLen;
        VECScale(&linAVec, &linAVec, invLinALen);
        VECScale(&linBVec, &linBVec, invLinBLen);
        Vec tmp;
        VECSubtract(lin_a->GetStartP(), lin_b->GetStartP(), &tmp);
        f32 tmpF = -VECDotProduct(&linAVec, &linBVec);
        f32 tmpF2 = VECDotProduct(&tmp, &linAVec);
        VECSquareMag(&tmp);  // result not used
        f32 tmpF3 = std::fabsf(1.0f - (tmpF * tmpF));
        if (!cM3d_IsZero(tmpF3)) {
            f32 tmpF4 = -VECDotProduct(&tmp, &linBVec);
            f32 tmpF7 = 1.0f / tmpF3;
            f32 outFloatAtmp = ((tmpF * tmpF4) - tmpF2) * tmpF7;
            *dst_a = outFloatAtmp * invLinALen;
            f32 outFloatBtmp = ((tmpF * tmpF2) - tmpF4) * tmpF7;
            *dst_b = outFloatBtmp * invLinBLen;
            return 3;
        } else {
            f32 tmpF5 = -tmpF2;
            f32 tmpF6 = 0.0f;
            if (tmpF5 < 0.0f || (tmpF5 > linALen)) {
                tmpF6 = linBLen;
                tmpF5 = (tmpF6 * tmpF) - tmpF2;
            }
            f32 tmpF7 = VECDotProduct(&tmp, &linBVec);
            if (tmpF5 < 0.0f || tmpF5 > linALen) {
                tmpF5 = 0.0f;
                tmpF6 = tmpF7;
            }
            if (tmpF6 < 0.0f || tmpF6 > linBLen) {
                tmpF5 = linALen;
                tmpF6 = tmpF7 + (-linALen * tmpF);
            }
            *dst_a = tmpF5 * invLinALen;
            *dst_b = tmpF6 * invLinBLen;
            return 2;
        }
    }
}

/* 8024ACA8-8024AE3C       .text cM3d_Cross_LinPla__FPC8cM3dGLinPC8cM3dGPlaP3Vecbb */
bool cM3d_Cross_LinPla(const cM3dGLin* lin, const cM3dGPla* pla, Vec* dst, bool a, bool b) {
    f32 startVal = pla->getPlaneFunc(lin->GetStartP());
    f32 endVal = pla->getPlaneFunc(lin->GetEndP());
    if (startVal * endVal > 0.0f) {
        *dst = lin->GetEnd();
        return false;
    } else {
        if (startVal >= 0.0f && endVal <= 0.0f) {
            if (a) {
                return cM3d_CrossInfLineVsInfPlane_proc(startVal, endVal, lin->GetStartP(), lin->GetEndP(), dst);
            }
        } else {
            if (b) {
                return cM3d_CrossInfLineVsInfPlane_proc(startVal, endVal, lin->GetStartP(), lin->GetEndP(), dst);
            }
        }
        *dst = lin->GetEnd();
        return false;
    }
}

const u32 BPCP_OUTCODE0 = 0x00000001;
const u32 BPCP_OUTCODE1 = 0x00000002;
const u32 BPCP_OUTCODE4 = 0x00000010;
const u32 BPCP_OUTCODE5 = 0x00000020;
const u32 BPCP_OUTCODE2 = 0x00000004;
const u32 BPCP_OUTCODE3 = 0x00000008;
const u32 BEVEL2D_OUTCODE0 = 0x00000001;
const u32 BEVEL2D_OUTCODE1 = 0x00000002;
const u32 BEVEL2D_OUTCODE2 = 0x00000004;
const u32 BEVEL2D_OUTCODE3 = 0x00000008;
const u32 BEVEL2D_OUTCODE4 = 0x00000010;
const u32 BEVEL2D_OUTCODE5 = 0x00000020;
const u32 BEVEL2D_OUTCODE6 = 0x00000040;
const u32 BEVEL2D_OUTCODE7 = 0x00000080;
const u32 BEVEL2D_OUTCODE8 = 0x00000100;
const u32 BEVEL2D_OUTCODE9 = 0x00000200;
const u32 BEVEL2D_OUTCODE10 = 0x00000400;
const u32 BEVEL2D_OUTCODE11 = 0x00000800;
const u32 BEVEL3D_OUTCODE0 = 0x00000001;
const u32 BEVEL3D_OUTCODE1 = 0x00000002;
const u32 BEVEL3D_OUTCODE2 = 0x00000004;
const u32 BEVEL3D_OUTCODE3 = 0x00000008;
const u32 BEVEL3D_OUTCODE4 = 0x00000010;
const u32 BEVEL3D_OUTCODE5 = 0x00000020;
const u32 BEVEL3D_OUTCODE6 = 0x00000040;
const u32 BEVEL3D_OUTCODE7 = 0x00000080;

inline u32 cM3d_CheckBoxEdgePlane_Bevel2DCheck(const Vec* param_0, const Vec* param_1, const Vec* param_2) {
    u32 ret = 0;
    if (-param_0->x + param_0->y > -param_1->x + param_2->y) {
        ret |= BEVEL2D_OUTCODE0;
    }
    if (-param_0->x + param_0->y < -param_2->x + param_1->y) {
        ret |= BEVEL2D_OUTCODE1;
    }
    if (param_0->x + param_0->y > param_2->x + param_2->y) {
        ret |= BEVEL2D_OUTCODE2;
    }
    if (param_0->x + param_0->y < param_1->x + param_1->y) {
        ret |= BEVEL2D_OUTCODE3;
    }
    if (-param_0->z + param_0->y > -param_1->z + param_2->y) {
        ret |= BEVEL2D_OUTCODE4;
    }
    if (-param_0->z + param_0->y < -param_2->z + param_1->y) {
        ret |= BEVEL2D_OUTCODE5;
    }
    if (param_0->z + param_0->y > param_2->z + param_2->y) {
        ret |= BEVEL2D_OUTCODE6;
    }
    if (param_0->z + param_0->y < param_1->z + param_1->y) {
        ret |= BEVEL2D_OUTCODE7;
    }
    if (-param_0->z + param_0->x > -param_1->z + param_2->x) {
        ret |= BEVEL2D_OUTCODE8;
    }
    if (-param_0->z + param_0->x < -param_2->z + param_1->x) {
        ret |= BEVEL2D_OUTCODE9;
    }
    if (param_0->z + param_0->x > param_2->z + param_2->x) {
        ret |= BEVEL2D_OUTCODE10;
    }
    if (param_0->z + param_0->x < param_1->z + param_1->x) {
        ret |= BEVEL2D_OUTCODE11;
    }
    return ret;
}

inline u32 cM3d_CheckBoxEdgePlane_Bevel3DCheck(const Vec* param_0, const Vec* param_1, const Vec* param_2) {
    u32 ret = 0;
    if (param_0->x + param_0->y + param_0->z > param_2->x + param_2->y + param_2->z) {
        ret |= BEVEL3D_OUTCODE0;
    }
    if (-param_0->x + param_0->y + param_0->z > -param_1->x + param_2->y + param_2->z) {
        ret |= BEVEL3D_OUTCODE1;
    }
    if (-param_0->x + param_0->y - param_0->z > -param_1->x + param_2->y - param_1->z) {
        ret |= BEVEL3D_OUTCODE2;
    }
    if (param_0->x + param_0->y - param_0->z > param_2->x + param_2->y - param_1->z) {
        ret |= BEVEL3D_OUTCODE3;
    }
    if (param_0->x - param_0->y + param_0->z > param_2->x - param_1->y + param_2->z) {
        ret |= BEVEL3D_OUTCODE4;
    }
    if (-param_0->x - param_0->y + param_0->z > -param_1->x - param_1->y + param_2->z) {
        ret |= BEVEL3D_OUTCODE5;
    }
    if (-param_0->x - param_0->y + param_0->z > -param_1->x - param_1->y + param_2->z) {
        ret |= BEVEL3D_OUTCODE6;
    }
    if (-param_0->x - param_0->y - param_0->z > -param_1->x - param_1->y - param_1->z) {
        ret |= BEVEL3D_OUTCODE7;
    }
    return ret;
}

/* 8024AE3C-8024BA18       .text cM3d_Cross_MinMaxBoxLine__FPC3VecPC3VecPC3VecPC3Vec */
bool cM3d_Cross_MinMaxBoxLine(const Vec* param_0, const Vec* param_1, const Vec* param_2, const Vec* param_3) {
    u32 uVar3 = 0;
    u32 uVar4 = 0;

    if (param_2->x > param_1->x) {
        if (param_3->x > param_1->x) {
            return false;
        }
        uVar3 |= BPCP_OUTCODE0;
    } else if (param_3->x > param_1->x) {
        uVar4 |= BPCP_OUTCODE0;
    }

    if ((uVar3 & BPCP_OUTCODE0) == 0 && param_2->x < param_0->x) {
        if ((uVar4 & BPCP_OUTCODE0) == 0 && param_3->x < param_0->x) {
            return false;
        }
        uVar3 |= BPCP_OUTCODE1;
    } else if ((uVar4 & BPCP_OUTCODE0) == 0 && param_3->x < param_0->x) {
        uVar4 |= BPCP_OUTCODE1;
    }

    if (param_2->z > param_1->z) {
        if (param_3->z > param_1->z) {
            return false;
        }
        uVar3 |= BPCP_OUTCODE4;
    } else if (param_3->z > param_1->z) {
        uVar4 |= BPCP_OUTCODE4;
    }

    if ((uVar3 & BPCP_OUTCODE4) == 0 && param_2->z < param_0->z) {
        if ((uVar4 & BPCP_OUTCODE4) == 0 && param_3->z < param_0->z) {
            return false;
        }
        uVar3 |= BPCP_OUTCODE5;
    } else if ((uVar4 & BPCP_OUTCODE4) == 0 && param_3->z < param_0->z) {
        uVar4 |= BPCP_OUTCODE5;
    }

    if (param_2->y > param_1->y) {
        if (param_3->y > param_1->y) {
            return false;
        }
        uVar3 |= BPCP_OUTCODE2;
    } else if (param_3->y > param_1->y) {
        uVar4 |= BPCP_OUTCODE2;
    }

    if ((uVar3 & BPCP_OUTCODE2) == 0 && param_2->y < param_0->y) {
        if ((uVar4 & BPCP_OUTCODE2) == 0 && param_3->y < param_0->y) {
            return false;
        }
        uVar3 |= BPCP_OUTCODE3;
    } else if ((uVar4 & BPCP_OUTCODE2) == 0 && param_3->y < param_0->y) {
        uVar4 |= BPCP_OUTCODE3;
    }

    if (uVar3 == 0) {
        return true;
    }
    if (uVar4 == 0) {
        return true;
    }

    uVar3 |= cM3d_CheckBoxEdgePlane_Bevel2DCheck(param_2, param_0, param_1) << 8;
    uVar4 |= cM3d_CheckBoxEdgePlane_Bevel2DCheck(param_3, param_0, param_1) << 8;
    if ((uVar3 & uVar4) != 0) {
        return false;
    }

    uVar3 |= cM3d_CheckBoxEdgePlane_Bevel3DCheck(param_2, param_0, param_1) << 0x18;
    uVar4 |= cM3d_CheckBoxEdgePlane_Bevel3DCheck(param_3, param_0, param_1) << 0x18;
    if ((uVar3 & uVar4) != 0) {
        return false;
    }

    cM3dGLin line(*param_2, *param_3);

    if ((uVar3 ^ uVar4) & BPCP_OUTCODE0) {
        cM3dGPla plane;
        plane.mNormal.x = 1.0f;
        plane.mNormal.y = 0.0f;
        plane.mNormal.z = 0.0f;
        plane.mD = -param_1->x;
        Vec cross;
        if (plane.cross(line, cross) && param_0->y <= cross.y && cross.y <= param_1->y
            && param_0->z <= cross.z && cross.z <= param_1->z)
        {
            return true;
        }
    }

    if ((uVar3 ^ uVar4) & BPCP_OUTCODE1) {
        cM3dGPla plane;
        plane.mNormal.x = -1.0f;
        plane.mNormal.y = 0.0f;
        plane.mNormal.z = 0.0f;
        plane.mD = param_0->x;
        Vec cross;
        if (plane.cross(line, cross) && param_0->y <= cross.y && cross.y <= param_1->y
            && param_0->z <= cross.z && cross.z <= param_1->z)
        {
            return true;
        }
    }

    if ((uVar3 ^ uVar4) & BPCP_OUTCODE2) {
        cM3dGPla plane;
        plane.mNormal.x = 0.0f;
        plane.mNormal.y = 1.0f;
        plane.mNormal.z = 0.0f;
        plane.mD = -param_1->y;
        Vec cross;
        if (plane.cross(line, cross) && param_0->x <= cross.x && cross.x <= param_1->x
            && param_0->z <= cross.z && cross.z <= param_1->z)
        {
            return true;
        }
    }

    if ((uVar3 ^ uVar4) & BPCP_OUTCODE3) {
        cM3dGPla plane;
        plane.mNormal.x = 0.0f;
        plane.mNormal.y = -1.0f;
        plane.mNormal.z = 0.0f;
        plane.mD = param_0->y;
        Vec cross;
        if (plane.cross(line, cross) && param_0->x <= cross.x && cross.x <= param_1->x
            && param_0->z <= cross.z && cross.z <= param_1->z)
        {
            return true;
        }
    }
    
    if ((uVar3 ^ uVar4) & BPCP_OUTCODE4) {
        cM3dGPla plane;
        plane.mNormal.x = 0.0f;
        plane.mNormal.y = 0.0f;
        plane.mNormal.z = 1.0f;
        plane.mD = -param_1->z;
        Vec cross;
        if (plane.cross(line, cross) && param_0->x <= cross.x && cross.x <= param_1->x
            && param_0->y <= cross.y && cross.y <= param_1->y)
        {
            return true;
        }
    }

    if ((uVar3 ^ uVar4) & BPCP_OUTCODE5) {
        cM3dGPla plane;
        plane.mNormal.x = 0.0f;
        plane.mNormal.y = 0.0f;
        plane.mNormal.z = -1.0f;
        plane.mD = param_0->z;
        Vec cross;
        if (plane.cross(line, cross) && param_0->x <= cross.x && cross.x <= param_1->x
            && param_0->y <= cross.y && cross.y <= param_1->y)
        {
            return true;
        }
    }

    return false;
}

/* 8024BA18-8024BB50       .text cM3d_InclusionCheckPosIn3PosBox3d__FPC3VecPC3VecPC3VecPC3Vecf */
bool cM3d_InclusionCheckPosIn3PosBox3d(const Vec* pVecA, const Vec* pVecB, const Vec* pVecC, const Vec* pVecD, f32 pF) {
    f32 min, max;
    if (pVecA->x < pVecB->x) {
        min = pVecA->x;
        max = pVecB->x;
    } else {
        min = pVecB->x;
        max = pVecA->x;
    }
    if (min > pVecC->x) {
        min = pVecC->x;
    } else if (max < pVecC->x) {
        max = pVecC->x;
    }
    if (min - pF > pVecD->x || max + pF < pVecD->x) {
        return false;
    }

    if (pVecA->z < pVecB->z) {
        min = pVecA->z;
        max = pVecB->z;
    } else {
        min = pVecB->z;
        max = pVecA->z;
    }
    if (min > pVecC->z) {
        min = pVecC->z;
    } else if (max < pVecC->z) {
        max = pVecC->z;
    }
    if (min - pF > pVecD->z || max + pF < pVecD->z) {
        return false;
    }

    if (pVecA->y < pVecB->y) {
        min = pVecA->y;
        max = pVecB->y;
    } else {
        min = pVecB->y;
        max = pVecA->y;
    }
    if (min > pVecC->y) {
        min = pVecC->y;
    } else if (max < pVecC->y) {
        max = pVecC->y;
    }
    if (min - pF > pVecD->y || max + pF < pVecD->y) {
        return false;
    }
    return true;
}

inline static bool cM3d_InclusionCheckPosIn3PosBox2d(
    f32 param_1, f32 param_2,
    f32 param_3, f32 param_4,
    f32 param_5, f32 param_6,
    f32 param_7, f32 param_8
) {
    f32 f31;
    f32 f30;
    if (param_1 < param_3) {
        f31 = param_1;
        f30 = param_3;
    } else {
        f31 = param_3;
        f30 = param_1;
    }

    if (f31 > param_5) {
        f31 = param_5;   
    } else if (f30 < param_5) {
        f30 = param_5;
    }

    if (f31 > param_7 || f30 < param_7) {
        return false;
    } 

    if (param_2 < param_4) {
        f31 = param_2;
        f30 = param_4;
    } else {
        f31 = param_4;
        f30 = param_2;
    }

    if (f31 > param_6) {
        f31 = param_6;
    } else if (f30 < param_6) {
        f30 = param_6;
    }
    
    if (f31 > param_8 || f30 < param_8) {
        return false;
    }
    return true;
}

/* 8024BB50-8024BD34       .text cM3d_CrossX_Tri__FPC8cM3dGTriPC3Vecf */
bool cM3d_CrossX_Tri(const cM3dGTri* tri, const Vec* pos, f32 f1) {
    if (cM3d_IsZero(tri->GetNP()->x)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        tri->mA.y,
        tri->mA.z,
        tri->mB.y,
        tri->mB.z,
        tri->mC.y,
        tri->mC.z,
        pos->y,
        pos->z
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        tri->mA.y,
        tri->mA.z,
        tri->mB.y,
        tri->mB.z,
        pos->y,
        pos->z
    );
    if (f12 <= f1
        &&
        cM3d_VectorProduct2d(
            tri->mB.y,
            tri->mB.z,
            tri->mC.y,
            tri->mC.z,
            pos->y,
            pos->z
        ) <= f1
        &&
        cM3d_VectorProduct2d(
            tri->mC.y,
            tri->mC.z,
            tri->mA.y,
            tri->mA.z,
            pos->y,
            pos->z
        ) <= f1
    ) {
        return true;
    }
    if (f12 >= -f1
        &&
        cM3d_VectorProduct2d(
            tri->mB.y,
            tri->mB.z,
            tri->mC.y,
            tri->mC.z,
            pos->y,
            pos->z
        ) >= -f1
        &&
        cM3d_VectorProduct2d(
            tri->mC.y,
            tri->mC.z,
            tri->mA.y,
            tri->mA.z,
            pos->y,
            pos->z
        ) >= -f1
    ) {
        return true;
    }
    return false;
}

/* 8024BD34-8024BF1C       .text cM3d_CrossX_Tri__FPC8cM3dGTriPC3Vec */
bool cM3d_CrossX_Tri(const cM3dGTri* tri, const Vec* pos) {
    if (cM3d_IsZero(tri->GetNP()->x)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        tri->mA.y,
        tri->mA.z,
        tri->mB.y,
        tri->mB.z,
        tri->mC.y,
        tri->mC.z,
        pos->y,
        pos->z
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        tri->mA.y,
        tri->mA.z,
        tri->mB.y,
        tri->mB.z,
        pos->y,
        pos->z
    );
    if (f12 <= 20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mB.y,
            tri->mB.z,
            tri->mC.y,
            tri->mC.z,
            pos->y,
            pos->z
        ) <= 20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mC.y,
            tri->mC.z,
            tri->mA.y,
            tri->mA.z,
            pos->y,
            pos->z
        ) <= 20.0f
    ) {
        return true;
    }
    if (f12 >= -20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mB.y,
            tri->mB.z,
            tri->mC.y,
            tri->mC.z,
            pos->y,
            pos->z
        ) >= -20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mC.y,
            tri->mC.z,
            tri->mA.y,
            tri->mA.z,
            pos->y,
            pos->z
        ) >= -20.0f
    ) {
        return true;
    }
    return false;
}

/* 8024BF1C-8024BFA0       .text cM3d_CrossX_Tri__FPC8cM3dGTriPC3VecPf */
bool cM3d_CrossX_Tri(const cM3dGTri* tri, const Vec* r30, f32* pcross_len) {
    if (cM3d_CrossX_Tri(tri, r30)) {
        *pcross_len = ((r30->y * -tri->GetNP()->y) - (r30->z * tri->GetNP()->z) - tri->GetD()) / tri->GetNP()->x;
        return true;
    } else {
        return false;
    }
}

/* 8024BFA0-8024C188       .text cM3d_CrossY_Tri__FPC8cM3dGTriPC3Vec */
bool cM3d_CrossY_Tri(const cM3dGTri* tri, const Vec* pos) {
    if (cM3d_IsZero(tri->GetNP()->y)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        tri->mA.z,
        tri->mA.x,
        tri->mB.z,
        tri->mB.x,
        tri->mC.z,
        tri->mC.x,
        pos->z,
        pos->x
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        tri->mA.z,
        tri->mA.x,
        tri->mB.z,
        tri->mB.x,
        pos->z,
        pos->x
    );
    if (f12 <= 20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mB.z,
            tri->mB.x,
            tri->mC.z,
            tri->mC.x,
            pos->z,
            pos->x
        ) <= 20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mC.z,
            tri->mC.x,
            tri->mA.z,
            tri->mA.x,
            pos->z,
            pos->x
        ) <= 20.0f
    ) {
        return true;
    }
    if (f12 >= -20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mB.z,
            tri->mB.x,
            tri->mC.z,
            tri->mC.x,
            pos->z,
            pos->x
        ) >= -20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mC.z,
            tri->mC.x,
            tri->mA.z,
            tri->mA.x,
            pos->z,
            pos->x
        ) >= -20.0f
    ) {
        return true;
    }
    return false;
}

/* 8024C188-8024C370       .text cM3d_CrossY_Tri__FRC3VecRC3VecRC3VecRC8cM3dGPlaPC3Vec */
bool cM3d_CrossY_Tri(const Vec& r3, const Vec& r4, const Vec& r5, const cM3dGPla& pla, const Vec* pos) {
    if (cM3d_IsZero(pla.GetNP()->y)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        r3.z,
        r3.x,
        r4.z,
        r4.x,
        r5.z,
        r5.x,
        pos->z,
        pos->x
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        r3.z,
        r3.x,
        r4.z,
        r4.x,
        pos->z,
        pos->x
    );
    if (f12 <= 20.0f
        &&
        cM3d_VectorProduct2d(
            r4.z,
            r4.x,
            r5.z,
            r5.x,
            pos->z,
            pos->x
        ) <= 20.0f
        &&
        cM3d_VectorProduct2d(
            r5.z,
            r5.x,
            r3.z,
            r3.x,
            pos->z,
            pos->x
        ) <= 20.0f
    ) {
        return true;
    }
    if (f12 >= -20.0f
        &&
        cM3d_VectorProduct2d(
            r4.z,
            r4.x,
            r5.z,
            r5.x,
            pos->z,
            pos->x
        ) >= -20.0f
        &&
        cM3d_VectorProduct2d(
            r5.z,
            r5.x,
            r3.z,
            r3.x,
            pos->z,
            pos->x
        ) >= -20.0f
    ) {
        return true;
    }
    return false;
}

/* 8024C370-8024C4D0       .text cM3d_CrossY_Tri_Front__FRC3VecRC3VecRC3VecPC3Vec */
bool cM3d_CrossY_Tri_Front(const Vec& r3, const Vec& r4, const Vec& r5, const Vec* pos) {
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        r3.z,
        r3.x,
        r4.z,
        r4.x,
        r5.z,
        r5.x,
        pos->z,
        pos->x
    )) {
        return false;
    }
    if (cM3d_VectorProduct2d(
            r3.z,
            r3.x,
            r4.z,
            r4.x,
            pos->z,
            pos->x
        ) >= -20.0f
        &&
        cM3d_VectorProduct2d(
            r4.z,
            r4.x,
            r5.z,
            r5.x,
            pos->z,
            pos->x
        ) >= -20.0f
        &&
        cM3d_VectorProduct2d(
            r5.z,
            r5.x,
            r3.z,
            r3.x,
            pos->z,
            pos->x
        ) >= -20.0f
    ) {
        return true;
    }
    return false;
}

/* 8024C4D0-8024C554       .text cM3d_CrossY_Tri__FPC8cM3dGTriPC3VecPf */
bool cM3d_CrossY_Tri(const cM3dGTri* tri, const Vec* r30, f32* pcross_len) {
    if (cM3d_CrossY_Tri(tri, r30)) {
        *pcross_len = ((r30->x * -tri->GetNP()->x) - (r30->z * tri->GetNP()->z) - tri->GetD()) / tri->GetNP()->y;
        return true;
    } else {
        return false;
    }
}

/* 8024C554-8024C738       .text cM3d_CrossY_Tri__FPC8cM3dGTriPC3Vecf */
bool cM3d_CrossY_Tri(const cM3dGTri* tri, const Vec* pos, f32 f1) {
    if (cM3d_IsZero(tri->GetNP()->y)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        tri->mA.z,
        tri->mA.x,
        tri->mB.z,
        tri->mB.x,
        tri->mC.z,
        tri->mC.x,
        pos->z,
        pos->x
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        tri->mA.z,
        tri->mA.x,
        tri->mB.z,
        tri->mB.x,
        pos->z,
        pos->x
    );
    if (f12 <= f1
        &&
        cM3d_VectorProduct2d(
            tri->mB.z,
            tri->mB.x,
            tri->mC.z,
            tri->mC.x,
            pos->z,
            pos->x
        ) <= f1
        &&
        cM3d_VectorProduct2d(
            tri->mC.z,
            tri->mC.x,
            tri->mA.z,
            tri->mA.x,
            pos->z,
            pos->x
        ) <= f1
    ) {
        return true;
    }
    if (f12 >= -f1
        &&
        cM3d_VectorProduct2d(
            tri->mB.z,
            tri->mB.x,
            tri->mC.z,
            tri->mC.x,
            pos->z,
            pos->x
        ) >= -f1
        &&
        cM3d_VectorProduct2d(
            tri->mC.z,
            tri->mC.x,
            tri->mA.z,
            tri->mA.x,
            pos->z,
            pos->x
        ) >= -f1
    ) {
        return true;
    }
    return false;
}

/* 8024C738-8024C828       .text cM3d_CrossY_Tri__FPC8cM3dGTriPC3VecPC10cM3d_RangePf */
bool cM3d_CrossY_Tri(const cM3dGTri* tri, const Vec* pos, const cM3d_Range* range, f32* pcross_len) {
    if (cM3d_IsZero(tri->GetNP()->y)) {
        return false;
    }
    Vec sp08;
    sp08.x = pos->x;
    sp08.y = range->start;
    sp08.z = pos->z;
    f32 f31 = tri->getPlaneFunc(&sp08);
    sp08.y = range->end;
    f32 f1 = tri->getPlaneFunc(&sp08);
    if ((f31 > 0.0f && f1 > 0.0f) || (f31 < 0.0f && f1 < 0.0f)) {
        return false;
    }
    return cM3d_CrossY_Tri(tri, pos, pcross_len);
}

/* 8024C828-8024CA0C       .text cM3d_CrossZ_Tri__FPC8cM3dGTriPC3Vecf */
bool cM3d_CrossZ_Tri(const cM3dGTri* tri, const Vec* pos, f32 f1) {
    if (cM3d_IsZero(tri->GetNP()->z)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        tri->mA.x,
        tri->mA.y,
        tri->mB.x,
        tri->mB.y,
        tri->mC.x,
        tri->mC.y,
        pos->x,
        pos->y
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        tri->mA.x,
        tri->mA.y,
        tri->mB.x,
        tri->mB.y,
        pos->x,
        pos->y
    );
    if (f12 <= f1
        &&
        cM3d_VectorProduct2d(
            tri->mB.x,
            tri->mB.y,
            tri->mC.x,
            tri->mC.y,
            pos->x,
            pos->y
        ) <= f1
        &&
        cM3d_VectorProduct2d(
            tri->mC.x,
            tri->mC.y,
            tri->mA.x,
            tri->mA.y,
            pos->x,
            pos->y
        ) <= f1
    ) {
        return true;
    }
    if (f12 >= -f1
        &&
        cM3d_VectorProduct2d(
            tri->mB.x,
            tri->mB.y,
            tri->mC.x,
            tri->mC.y,
            pos->x,
            pos->y
        ) >= -f1
        &&
        cM3d_VectorProduct2d(
            tri->mC.x,
            tri->mC.y,
            tri->mA.x,
            tri->mA.y,
            pos->x,
            pos->y
        ) >= -f1
    ) {
        return true;
    }
    return false;
}

/* 8024CA0C-8024CBF4       .text cM3d_CrossZ_Tri__FPC8cM3dGTriPC3Vec */
bool cM3d_CrossZ_Tri(const cM3dGTri* tri, const Vec* pos) {
    if (cM3d_IsZero(tri->GetNP()->z)) {
        return false;
    }
    if (!cM3d_InclusionCheckPosIn3PosBox2d(
        tri->mA.x,
        tri->mA.y,
        tri->mB.x,
        tri->mB.y,
        tri->mC.x,
        tri->mC.y,
        pos->x,
        pos->y
    )) {
        return false;
    }
    f32 f12 = cM3d_VectorProduct2d(
        tri->mA.x,
        tri->mA.y,
        tri->mB.x,
        tri->mB.y,
        pos->x,
        pos->y
    );
    if (f12 <= 20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mB.x,
            tri->mB.y,
            tri->mC.x,
            tri->mC.y,
            pos->x,
            pos->y
        ) <= 20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mC.x,
            tri->mC.y,
            tri->mA.x,
            tri->mA.y,
            pos->x,
            pos->y
        ) <= 20.0f
    ) {
        return true;
    }
    if (f12 >= -20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mB.x,
            tri->mB.y,
            tri->mC.x,
            tri->mC.y,
            pos->x,
            pos->y
        ) >= -20.0f
        &&
        cM3d_VectorProduct2d(
            tri->mC.x,
            tri->mC.y,
            tri->mA.x,
            tri->mA.y,
            pos->x,
            pos->y
        ) >= -20.0f
    ) {
        return true;
    }
    return false;
}

/* 8024CBF4-8024CC78       .text cM3d_CrossZ_Tri__FPC8cM3dGTriPC3VecPf */
bool cM3d_CrossZ_Tri(const cM3dGTri* tri, const Vec* r30, f32* pcross_len) {
    if (cM3d_CrossZ_Tri(tri, r30)) {
        *pcross_len = ((r30->x * -tri->GetNP()->x) - (r30->y * tri->GetNP()->y) - tri->GetD()) / tri->GetNP()->z;
        return true;
    } else {
        return false;
    }
}

/* 8024CC78-8024CD50       .text cM3d_Cross_LinTri__FPC8cM3dGLinPC8cM3dGTriP3Vecbb */
bool cM3d_Cross_LinTri(const cM3dGLin* lin, const cM3dGTri* tri, Vec* dst, bool a, bool b) {
    if (!cM3d_Cross_LinPla(lin, tri, dst, a, b)) {
        return false;
    }
    if ((std::fabsf(tri->GetNP()->x) < 0.008f || cM3d_CrossX_Tri(tri, dst)) &&
        (std::fabsf(tri->GetNP()->y) < 0.008f || cM3d_CrossY_Tri(tri, dst)) &&
        (std::fabsf(tri->GetNP()->z) < 0.008f || cM3d_CrossZ_Tri(tri, dst))
    ) {
        return true;
    } else {
        return false;
    }
}

/* 8024CD50-8024CE0C       .text cM3d_Cross_LinTri_Easy__FPC8cM3dGTriPC3Vec */
bool cM3d_Cross_LinTri_Easy(const cM3dGTri* tri, const Vec* r31) {
    if ((cM3d_IsZero(tri->GetNP()->x) || cM3d_CrossX_Tri(tri, r31)) &&
        (cM3d_IsZero(tri->GetNP()->y) || cM3d_CrossY_Tri(tri, r31)) &&
        (cM3d_IsZero(tri->GetNP()->z) || cM3d_CrossZ_Tri(tri, r31))
    ) {
        return true;
    } else {
        return false;
    }
}

/* 8024CE0C-8024CE54       .text cM3d_Cross_SphPnt__FPC8cM3dGSphPC3Vec */
bool cM3d_Cross_SphPnt(const cM3dGSph* sph, const Vec* point) {
    return cM3d_LenSq(sph->GetCP(), point) <= sph->GetR() * sph->GetR();
}

/* 8024CE54-8024D0BC       .text cM3d_Cross_LinSph__FPC8cM3dGLinPC8cM3dGSphP3Vec */
bool cM3d_Cross_LinSph(const cM3dGLin* line, const cM3dGSph* sph, Vec* param_2) {
    Vec lin_vec;
    cXyz vec;
    const Vec* center = sph->GetCP();

    f32 max_x = center->x + sph->GetR();
    if (max_x < line->GetStartP()->x && max_x < line->GetEndP()->x) {
        return false;
    }
    f32 min_x = center->x - sph->GetR();
    if (min_x > line->GetStartP()->x && min_x > line->GetEndP()->x) {
        return false;
    }

    f32 max_y = center->y + sph->GetR();
    if (max_y < line->GetStartP()->y && max_y < line->GetEndP()->y) {
        return false;
    }
    f32 min_y = center->y - sph->GetR();
    if (min_y > line->GetStartP()->y && min_y > line->GetEndP()->y) {
        return false;
    }

    f32 max_z = center->z + sph->GetR();
    if (max_z < line->GetStartP()->z && max_z < line->GetEndP()->z) {
        return false;
    }
    f32 min_z = center->z - sph->GetR();
    if (min_z > line->GetStartP()->z && min_z > line->GetEndP()->z) {
        return false;
    }

    VECSubtract(line->GetEndP(), line->GetStartP(), &lin_vec);
    f32 len_sq = VECSquareMag(&lin_vec);
    if (cM3d_IsZero(len_sq)) {
        return false;
    }

    VECSubtract(center, line->GetStartP(), &vec);
    f32 proj = VECDotProduct(&vec, &lin_vec) / len_sq;
    if (proj < 0.0f || proj > 1.0f) {
        if (line->GetStartP()->abs2(*center) < line->GetEndP()->abs2(*center)) {
            if (cM3d_Cross_SphPnt(sph, line->GetStartP())) {
                param_2->x = line->GetStartP()->x;
                param_2->y = line->GetStartP()->y;
                param_2->z = line->GetStartP()->z;
                return true;
            }
        } else {
            if (cM3d_Cross_SphPnt(sph, line->GetEndP())) {
                param_2->x = line->GetEndP()->x;
                param_2->y = line->GetEndP()->y;
                param_2->z = line->GetEndP()->z;
                return true;
            }
        }
        return false;
    }

    Vec proj_vec;
    VECScale(&lin_vec, &proj_vec, proj);
    VECAdd(&proj_vec, line->GetStartP(), param_2);
    if (cM3d_LenSq(param_2, center) <= sph->GetR() * sph->GetR()) {
        return true;
    }
    return false;
}

/* 8024D0BC-8024D378       .text cM3d_Cross_LinSph_CrossPos__FRC8cM3dGSphRC8cM3dGLinP3VecP3Vec */
int cM3d_Cross_LinSph_CrossPos(const cM3dGSph& sph, const cM3dGLin& line, Vec* param_2, Vec* param_3) {
    int ret;
    Vec line_vec, vec;
    VECSubtract(line.GetEndP(), line.GetStartP(), &line_vec);
    VECSubtract(line.GetStartP(), sph.GetCP(), &vec);
    f32 len_sq = VECDotProduct(&line_vec, &line_vec);
    f32 dVar9 = VECDotProduct(&line_vec, &vec) * 2.0f;
    f32 dVar6 = VECDotProduct(&vec, &vec) - sph.GetR() * sph.GetR();

    if (cM3d_IsZero(len_sq)) {
        if (cM3d_IsZero(dVar9)) {
            return 0;
        } else {
            ret = 1;
            Vec vec2;
            VECScale(&line_vec, &vec2, -dVar6 / dVar9);
            VECAdd(&vec2, line.GetStartP(), param_2);
        }
    } else {
        f32 f11 = dVar9 * dVar9 - len_sq * 4.0f * dVar6;
        if (cM3d_IsZero(f11)) {
            ret = 1;
            Vec vec2;
            VECScale(&line_vec, &vec2, -dVar9 / (len_sq * 2.0f));
            VECAdd(&vec2, line.GetStartP(), param_2);
        } else if (f11 < 0.0f) {
            ret = 0;
        } else {
            ret = 2;
            f32 f1 = 1.0f / (len_sq * 2.0f);
            Vec vec2;
            f32 scale1 = f1 * (-dVar9 + std::sqrtf(f11));
            f32 scale2 = f1 * (-dVar9 - std::sqrtf(f11));
            VECScale(&line_vec, &vec2, scale1);
            VECAdd(&vec2, line.GetStartP(), param_2);
            VECScale(&line_vec, &vec2, scale2);
            VECAdd(&vec2, line.GetStartP(), param_3);
        }
    }

    return ret;
}

/* 8024D378-8024DB34       .text cM3d_Cross_CylSph__FPC8cM3dGCylPC8cM3dGSphP3VecPf */
bool cM3d_Cross_CylSph(const cM3dGCyl* pcyl, const cM3dGSph* psph, Vec* param_2, f32* pcross_len) {
    const Vec* pnow_sph_center = psph->GetCP();
    JUT_ASSERT(DEMO_SELECT(2499, 2498), !isnan(pnow_sph_center->x));
    JUT_ASSERT(DEMO_SELECT(2500, 2499), !isnan(pnow_sph_center->y));
    JUT_ASSERT(DEMO_SELECT(2501, 2500), !isnan(pnow_sph_center->z));
    JUT_ASSERT(DEMO_SELECT(2502, 2501), !isnan(psph->GetR()));
    const Vec* pnow_cyl_center = pcyl->GetCP();
    JUT_ASSERT(DEMO_SELECT(2504, 2503), !isnan(pnow_cyl_center->x));
    JUT_ASSERT(DEMO_SELECT(2505, 2504), !isnan(pnow_cyl_center->y));
    JUT_ASSERT(DEMO_SELECT(2506, 2505), !isnan(pnow_cyl_center->z));
    JUT_ASSERT(DEMO_SELECT(2507, 2506), !isnan(pcyl->GetH()));
    JUT_ASSERT(DEMO_SELECT(2508, 2507), !isnan(pcyl->GetR()));
    f32 radius_sum = pcyl->GetR() + psph->GetR();
    f32 dist = std::sqrtf(cM3d_Len2dSq(pnow_sph_center->x, pnow_sph_center->z, pnow_cyl_center->x, pnow_cyl_center->z));

    if (radius_sum < dist) {
        return false;
    }

    if (pnow_sph_center->y + psph->GetR() >= pnow_cyl_center->y
        && pnow_sph_center->y - psph->GetR() <= pnow_cyl_center->y + pcyl->GetH())
    {
        *pcross_len = radius_sum - dist;
        if (!cM3d_IsZero(dist)) {
            f32 scale = pcyl->GetR() / dist;
            if (scale <= 1.0f) {
                Vec delta;
                VECSubtract(pnow_sph_center, pnow_cyl_center, &delta);
                VECScale(&delta, &delta, scale);
                VECAdd(&delta, pnow_cyl_center, param_2);
            } else {
                *param_2 = *pnow_sph_center;
            }
        } else {
            *param_2 = *pnow_sph_center;
        }
#if VERSION > VERSION_DEMO
        JUT_ASSERT(2539, !isnan(*pcross_len));
#endif
        return true;
    }

    return false;
}

/* 8024DB34-8024E1B4       .text cM3d_Cross_SphSph__FPC8cM3dGSphPC8cM3dGSphPfPf */
bool cM3d_Cross_SphSph(const cM3dGSph* i_a, const cM3dGSph* i_b, f32* param_2, f32* i_pcc_crosslen) {
    JUT_ASSERT(DEMO_SELECT(2566, 2565), !isnan(i_a->GetCP()->x));
    JUT_ASSERT(DEMO_SELECT(2567, 2566), !isnan(i_a->GetCP()->y));
    JUT_ASSERT(DEMO_SELECT(2568, 2567), !isnan(i_a->GetCP()->z));
    JUT_ASSERT(DEMO_SELECT(2569, 2568), !isnan(i_a->GetR()));

    JUT_ASSERT(DEMO_SELECT(2570, 2569), !isnan(i_b->GetCP()->x));
    JUT_ASSERT(DEMO_SELECT(2571, 2570), !isnan(i_b->GetCP()->y));
    JUT_ASSERT(DEMO_SELECT(2572, 2571), !isnan(i_b->GetCP()->z));
    JUT_ASSERT(DEMO_SELECT(2573, 2572), !isnan(i_b->GetR()));

    Vec delta;
    VECSubtract(i_a->GetCP(), i_b->GetCP(), &delta);
    *param_2 = VECMag(&delta);
    *i_pcc_crosslen = i_a->GetR() + i_b->GetR() - *param_2;
    if (*i_pcc_crosslen > G_CM3D_F_ABS_MIN) {
        JUT_ASSERT(DEMO_SELECT(2583, 2582), !isnan(*i_pcc_crosslen));
        return true;
    } else {
        *i_pcc_crosslen = 0.0f;
        JUT_ASSERT(DEMO_SELECT(2588, 2587), !isnan(*i_pcc_crosslen));
        return false;
    }
}

/* 8024E1B4-8024E288       .text cM3d_Cross_SphSph__FPC8cM3dGSphPC8cM3dGSphP3Vec */
bool cM3d_Cross_SphSph(const cM3dGSph* sph_a, const cM3dGSph* sph_b, Vec* dst) {
    f32 centerDist;
    f32 overlapLen;
    if (cM3d_Cross_SphSph(sph_a, sph_b, &centerDist, &overlapLen)) {
        if (!cM3d_IsZero(centerDist)) {
            // could be an inlined function
            f32 tmpF = sph_b->GetR() / centerDist;
            Vec tmp;
            VECSubtract(&sph_a->GetC(), &sph_b->GetC(), &tmp);
            VECScale(&tmp, &tmp, tmpF);
            VECAdd(&tmp, &sph_b->GetC(), dst);
        } else {
            *dst = sph_a->GetC();
        }
        return true;
    } else {
        return false;
    }
}

/* 8024E288-8024E330       .text cM3d_CalcSphVsTriCrossPoint__FPC8cM3dGSphPC8cM3dGTriP3Vec */
void cM3d_CalcSphVsTriCrossPoint(const cM3dGSph* sph, const cM3dGTri* tri, Vec* dst) {
    Vec tmp2;
    Vec tmp;
    VECAdd(&tri->mA, &tri->mB, &tmp);
    VECScale(&tmp, &tmp2, 0.5f);
    f32 sqDist = VECSquareDistance(&tmp2, &sph->GetC());
    if (cM3d_IsZero(sqDist)) {
        *dst = sph->GetC();
    } else {
        cM3d_InDivPos2(&sph->GetC(), &tmp2, sph->GetR() / sqDist, dst);
    }
}

inline bool cM3d_Cross_LinSph(cM3dGLin const* line, cM3dGSph const* sph) {
    Vec vec;
    return cM3d_Cross_LinSph(line, sph, &vec);
}

/* 8024E330-8024E694       .text cM3d_Cross_SphTri__FPC8cM3dGSphPC8cM3dGTriP3Vec */
bool cM3d_Cross_SphTri(const cM3dGSph* sph, const cM3dGTri* tri, Vec* param_2) {
    if (!cM3d_InclusionCheckPosIn3PosBox3d(&tri->mA, &tri->mB, &tri->mC, sph->GetCP(), sph->GetR())) {
        return false;
    }

    f32 dist = cM3d_SignedLenPlaAndPos(tri, sph->GetCP());
    if (std::fabsf(dist) > sph->GetR()) {
        return false;
    }

    Vec vec1, vec2;
    VECScale(tri->GetNP(), &vec2, dist);
    VECSubtract(sph->GetCP(), &vec2, &vec1);

    if (std::fabsf(tri->GetNP()->y) > 0.5f) {
        if (cM3d_CrossY_Tri(tri, &vec1, 0.0f)) {
            if (param_2 != NULL) {
                cM3d_CalcSphVsTriCrossPoint(sph, tri, param_2);
            }
            return true;
        }
    } else if (std::fabsf(tri->GetNP()->x) > 0.5f) {
        if (cM3d_CrossX_Tri(tri, &vec1, 0.0f)) {
            if (param_2 != NULL) {
                cM3d_CalcSphVsTriCrossPoint(sph, tri, param_2);
            }
            return true;
        }
    } else {
        if (cM3d_CrossZ_Tri(tri, &vec1, 0.0f)) {
            if (param_2 != NULL) {
                cM3d_CalcSphVsTriCrossPoint(sph, tri, param_2);
            }
            return true;
        }
    }

    cM3dGLin line1(tri->mA, tri->mB);
    if (cM3d_Cross_LinSph(&line1, sph)) {
        if (param_2 != NULL) {
            cM3d_CalcSphVsTriCrossPoint(sph, tri, param_2);
        }
        return true;
    }

    cM3dGLin line2(tri->mB, tri->mC);
    if (cM3d_Cross_LinSph(&line2, sph)) {
        if (param_2 != NULL) {
            cM3d_CalcSphVsTriCrossPoint(sph, tri, param_2);
        }
        return true;
    }

    cM3dGLin line3(tri->mC, tri->mA);
    if (cM3d_Cross_LinSph(&line3, sph)) {
        if (param_2 != NULL) {
            cM3d_CalcSphVsTriCrossPoint(sph, tri, param_2);
        }
        return true;
    }

    return false;
}

/* 8024E694-8024EF80       .text cM3d_Cross_CylCyl__FPC8cM3dGCylPC8cM3dGCylPf */
bool cM3d_Cross_CylCyl(const cM3dGCyl* i_cyl1, const cM3dGCyl* i_cyl2, f32* i_pcross_len) {
    const Vec& c1 = i_cyl1->GetC();
    JUT_ASSERT(DEMO_SELECT(2827, 2826), !isnan(c1.x));
    JUT_ASSERT(DEMO_SELECT(2828, 2827), !isnan(c1.y));
    JUT_ASSERT(DEMO_SELECT(2829, 2828), !isnan(c1.z));
    JUT_ASSERT(DEMO_SELECT(2830, 2829), !isnan(i_cyl1->GetR()));
    JUT_ASSERT(DEMO_SELECT(2831, 2830), !isnan(i_cyl1->GetH()));
    const Vec& c2 = i_cyl2->GetC();
    JUT_ASSERT(DEMO_SELECT(2833, 2832), !isnan(c2.x));
    JUT_ASSERT(DEMO_SELECT(2834, 2833), !isnan(c2.y));
    JUT_ASSERT(DEMO_SELECT(2835, 2834), !isnan(c2.z));
    JUT_ASSERT(DEMO_SELECT(2836, 2835), !isnan(i_cyl2->GetR()));
    JUT_ASSERT(DEMO_SELECT(2837, 2836), !isnan(i_cyl2->GetH()));
    
    f32 delta_x = c1.x - c2.x;
    f32 delta_z = c1.z - c2.z;
    f32 dist_sq = delta_x * delta_x + delta_z * delta_z;
    f32 radius_sum = i_cyl1->GetR() + i_cyl2->GetR();
    
    if (dist_sq > radius_sum * radius_sum) {
        *i_pcross_len = 0.0f;
        JUT_ASSERT(DEMO_SELECT(2850, 2849), !isnan(*i_pcross_len));
        return false;
    }

    if (c1.y + i_cyl1->GetH() < c2.y || c1.y > c2.y + i_cyl2->GetH()) {
        *i_pcross_len = 0.0f;
        JUT_ASSERT(DEMO_SELECT(2858, 2857), !isnan(*i_pcross_len));
        return false;
    }

    *i_pcross_len = radius_sum - std::sqrtf(dist_sq);
    JUT_ASSERT(DEMO_SELECT(2865, 2864), !isnan(*i_pcross_len));
    return true;
}

/* 8024EF80-8024F11C       .text cM3d_Cross_CylCyl__FPC8cM3dGCylPC8cM3dGCylP3Vec */
bool cM3d_Cross_CylCyl(const cM3dGCyl* cyl1, const cM3dGCyl* cyl2, Vec* param_2) {
    const Vec& center1 = cyl1->GetC();
    const Vec& center2 = cyl2->GetC();
    f32 delta_x = center1.x - center2.x;
    f32 delta_z = center1.z - center2.z;
    f32 dist_sq = delta_x * delta_x + delta_z * delta_z;
    f32 radius_sum = cyl1->GetR() + cyl2->GetR();
    
    if (dist_sq > radius_sum * radius_sum) {
        return false;
    }

    if (center1.y + cyl1->GetH() < center2.y || center1.y > center2.y + cyl2->GetH()) {
        return false;
    }

    f32 dist = std::sqrtf(dist_sq);
    if (!cM3d_IsZero(dist)) {
        f32 scale = cyl2->GetR() / dist;
        param_2->y = center2.y + cyl2->GetH() * 0.5f;
        f32 tmp = center1.y;
        if (param_2->y < tmp) {
            param_2->y = tmp;
        } else {
            tmp += cyl1->GetH();
            if (param_2->y > tmp) {
                param_2->y = tmp;
            }
        }
        param_2->x = center2.x + scale * (center1.x - center2.x);
        param_2->z = center2.z + scale * (center1.z - center2.z);
    } else {
        *param_2 = center2;
    }

    return true;
}

/* 8024F11C-8024F410       .text cM3d_Cross_CylTri__FPC8cM3dGCylPC8cM3dGTriP3Vec */
bool cM3d_Cross_CylTri(const cM3dGCyl* cyl, const cM3dGTri* tri, Vec* param_2) {
    const Vec& center = cyl->GetC();
    f32 top_y = center.y + cyl->GetH();
    
    if ((center.y > tri->mA.y && center.y > tri->mB.y && center.y > tri->mC.y)
        || (top_y < tri->mA.y && top_y < tri->mB.y && top_y < tri->mC.y))
    {
        return false;
    }

    Vec vec1, vec2;
    f32 min_len_sq = G_CM3D_F_INF;
    if (cM3d_Cross_CylPntPnt(cyl, &tri->mA, &tri->mB, &vec1, &vec2)) {
        min_len_sq = cM3d_LenSq(&vec1, &tri->mA);
        *param_2 = vec1;
    }
    if (cM3d_Cross_CylPntPnt(cyl, &tri->mC, &tri->mB, &vec1, &vec2)) {
        f32 len_sq = cM3d_LenSq(&vec1, &tri->mC);
        if (min_len_sq > len_sq) {
            min_len_sq = len_sq;
            *param_2 = vec1;
        }
    }
    if (cM3d_Cross_CylPntPnt(cyl, &tri->mA, &tri->mC, &vec1, &vec2)) {
        f32 len_sq = cM3d_LenSq(&vec1, &tri->mA);
        if (min_len_sq > len_sq) {
            min_len_sq = len_sq;
            *param_2 = vec1;
        }
    }

    if (min_len_sq != G_CM3D_F_INF) {
        return true;
    }

    cM3d_Range range;
    range.start = center.y;
    range.end = top_y;
    f32 tmp;
    if (cM3d_CrossY_Tri(tri, &center, &range, &tmp)) {
        Vec vec3, vec4, vec5, vec6;
        vec3 = center;
        vec3.y = tmp;
        VECAdd(&tri->mA, &tri->mB, &vec6);
        VECScale(&vec6, &vec4, 0.5f);
        VECSubtract(&vec4, &vec3, &vec5);
        f32 dist = std::sqrtf(vec5.x * vec5.x + vec5.z * vec5.z);

        if (cM3d_IsZero(dist)) {
            param_2->x = vec4.x;
            param_2->y = vec4.y;
            param_2->z = vec4.z;
        } else {
            cM3d_InDivPos1(&vec3, &vec5, cyl->GetR() / dist, param_2);
        }

        return true;
    }

    return false;
}

/* 8024F410-8024FA90       .text cM3d_Cross_CylLin__FPC8cM3dGCylPC8cM3dGLinP3VecP3Vec */
int cM3d_Cross_CylLin(const cM3dGCyl* cyl, const cM3dGLin* line, Vec* param_2, Vec* param_3) {
    f32 ratio;
    f32 f2;
    f32 fVar5;
    f32 fVar2;
    f32 fVar1;
    f32 fVar6;
    f32 fVar4;
    BOOL bVar4;
    BOOL bVar3;
    BOOL bVar6;
    BOOL bVar5;
    u32 uVar11;
    f32 sp28;
    f32 r_sq;
    int count;

    ratio = 0.0f;
    f2 = 0.0f;
    uVar11 = 0;

    if (cM3d_Cross_CylPnt(cyl, line->GetStartP()) && cM3d_Cross_CylPnt(cyl, line->GetEndP())) {
        *param_2 = *line->GetStartP();
        *param_3 = *line->GetEndP();
        return 2;
    }

    Vec vec1, vec2, vec3;
    Vec vec[4];
    const cXyz* center = cyl->GetCP();
    VECSubtract(line->GetStartP(), center, &vec1);
    VECSubtract(line->GetEndP(), center, &vec2);
    VECSubtract(&vec2, &vec1, &vec3);
    r_sq = cyl->GetR() * cyl->GetR();

    if (!cM3d_IsZero(vec3.y)) {
        ratio = -vec1.y / vec3.y;
        if (ratio >= 0.0f && ratio <= 1.0f) {
            f32 x = vec1.x + vec3.x * ratio;
            f32 z = vec1.z + vec3.z * ratio;
            if (x * x + z * z < r_sq) {
                uVar11 |= 1;
                vec[0].x = x + center->x;
                vec[0].y = center->y;
                vec[0].z = z + center->z;
            }
        }

        ratio = (cyl->GetH() - vec1.y) / vec3.y;
        if (ratio >= 0.0f && ratio <= 1.0f) {
            f32 x = vec1.x + vec3.x * ratio;
            f32 z = vec1.z + vec3.z * ratio;
            if (x * x + z * z < r_sq) {
                uVar11 |= 2;
                vec[1].x = x + center->x;
                vec[1].y = center->y + cyl->GetH();
                vec[1].z = z + center->z;
            }
        }
    }

    bVar4 = false;
    bVar3 = false;
    fVar5 = vec3.x * vec3.x + vec3.z * vec3.z;
    fVar2 = (vec3.x * vec1.x + vec3.z * vec1.z) * 2.0f;
    fVar1 = vec1.x * vec1.x + vec1.z * vec1.z - r_sq;

    f32 sp0C = fVar5 * 2.0f;
    if (!cM3d_IsZero(sp0C)) {
        fVar6 = fVar2 * fVar2 - fVar5 * 4.0f * fVar1;
        if (fVar6 < 0.0f) {
            return 0;
        }
        if (fVar6 > 0.0f) {
            bVar4 = bVar3 = true;
        } else {
            bVar4 = true;
            bVar3 = false;
        }
        fVar4 = std::sqrtf(fVar6);
        if (bVar4) {
            ratio = (-fVar2 + fVar4) / sp0C;
        }
        if (bVar3) {
            f2 = (-fVar2 - fVar4) / sp0C;
        }
    } else {
        if (!cM3d_IsZero(fVar2)) {
            bVar4 = true;
            bVar3 = false;
            ratio = -fVar1 / fVar2;
        } else {
            return 0;
        }
    }

    if (bVar4 && !bVar3) {
        if (0.0f > ratio || ratio > 1.0f) {
            return 0;
        }
    } else {
        bVar6 = 0.0f > ratio || ratio > 1.0f;
        bVar5 = 0.0f > f2 || f2 > 1.0f;
        if (bVar6 && bVar5) {
            return 0;
        }
        if (bVar6) {
            bVar4 = false;
        }
        if (bVar5) {
            bVar3 = false;
        }
    }

    if (bVar4) {
        sp28 = vec1.y + ratio * vec3.y;
        if (sp28 < 0.0f || sp28 > cyl->GetH()) {
            bVar4 = false;
        }
    }
    if (bVar3) {
        sp28 = vec1.y + f2 * vec3.y;
        if (sp28 < 0.0f || sp28 > cyl->GetH()) {
            bVar3 = false;
        }
    }

    if (!bVar4 && !bVar3) {
        return 0;
    }

    if (bVar4 && bVar3) {
        Vec vec5, vec6;
        VECAdd(&vec1, center, &vec5);
        uVar11 |= 4;
        VECScale(&vec3, &vec6, ratio);
        VECAdd(&vec6, &vec5, &vec[2]);
        uVar11 |= 8;
        VECScale(&vec3, &vec6, f2);
        VECAdd(&vec6, &vec5, &vec[3]);
    } else if (bVar4) {
        uVar11 |= 4;
        Vec vec5, vec6;
        VECScale(&vec3, &vec5, ratio);
        VECAdd(&vec5, &vec1, &vec6);
        VECAdd(&vec6, center, &vec[2]);
    } else if (bVar3) {
        uVar11 |= 4;
        Vec vec5, vec6;
        VECScale(&vec3, &vec5, f2);
        VECAdd(&vec5, &vec1, &vec6);
        VECAdd(&vec6, center, &vec[2]);
    }

    count = 0;
    for (int i = 0; i < 4; i++) {
        if (uVar11 & (1 << i)) {
            if (count == 0) {
                *param_2 = vec[i];
            } else if (count == 1) {
                // Bug? This check was changed to the following for TP:
                // if (cM3d_LenSq(line->GetStartP(), param_2) < cM3d_LenSq(line->GetStartP(), &vec[i])) {
                if (cM3d_LenSq(param_2, line->GetStartP()) < cM3d_LenSq(param_2, &vec[i])) {
                    *param_3 = vec[i];
                } else {
                    *param_3 = *param_2;
                    *param_2 = vec[i];
                }
                break;
            }
            count++;
        }
    }
    return count;
}

/* 8024FA90-8024FB04       .text cM3d_Cross_CylPntPnt__FPC8cM3dGCylPC3VecPC3VecP3VecP3Vec */
int cM3d_Cross_CylPntPnt(const cM3dGCyl* cyl, const Vec* a, const Vec* b, Vec* dst_a, Vec* dst_b) {
    cM3dGLin lin;
    lin.SetStartEnd(*a, *b);
    return cM3d_Cross_CylLin(cyl, &lin, dst_a, dst_b);
}

/* 8024FB04-8024FB68       .text cM3d_Cross_CylPnt__FPC8cM3dGCylPC3Vec */
bool cM3d_Cross_CylPnt(const cM3dGCyl* cyl, const Vec* pt) {
    const cXyz& center = cyl->GetC();
    f32 dX = center.x - pt->x;
    f32 dZ = center.z - pt->z;
    f32 y = center.y;
    f32 maxY = y + cyl->GetH();
    if (dX * dX + dZ * dZ < cyl->GetR() * cyl->GetR() && y < pt->y && maxY > pt->y) {
        return true;
    } else {
        return false;
    }
}

/* 8024FB68-8024FF10       .text cM3d_Cross_CpsCps__FRC8cM3dGCpsRC8cM3dGCpsP3Vec */
bool cM3d_Cross_CpsCps(const cM3dGCps& cps1, const cM3dGCps& cps2, Vec* param_2) {
    f32 f1, f2;
    int iVar1 = cM3d_Check_LinLin(&cps1, &cps2, &f1, &f2);

    if (iVar1 == 1) {
        return false;
    }

    if (iVar1 == 2) {
        if (f1 > 0.0f && f1 < 1.0f && f2 > 0.0f && f2 < 1.0f) {
            Vec pos1, pos2;
            cps1.CalcPos(&pos1, f1);
            cps2.CalcPos(&pos2, f2);
            if (VECDistance(&pos1, &pos2) < cps1.GetR() + cps2.GetR()) {
                VECAdd(&pos1, &pos2, param_2);
                VECScale(param_2, param_2, 0.5f);
                return true;
            }
        }
    } else if (iVar1 == 3) {
        Vec pos1, pos2;
        if (f1 < 0.0f) {
            pos1 = cps1.GetStart();
            if (f2 < 0.0f) {
                pos2 = cps2.GetStart();
            } else if (f2 > 1.0f) {
                pos2 = cps2.GetEnd();
            } else {
                cps2.CalcPos(&pos2, f2);
            }
        } else if (f1 > 1.0f) {
            pos1 = cps1.GetEnd();
            if (f2 < 0.0f) {
                pos2 = cps2.GetStart();
            } else if (f2 > 1.0f) {
                pos2 = cps2.GetEnd();
            } else {
                cps2.CalcPos(&pos2, f2);
            }
        } else {
            cps1.CalcPos(&pos1, f1);
            if (f2 < 0.0f) {
                pos2 = cps2.GetStart();
            } else if (f2 > 1.0f) {
                pos2 = cps2.GetEnd();
            } else {
                cps2.CalcPos(&pos2, f2);
            }
        }

        if (VECDistance(&pos1, &pos2) < cps1.GetR() + cps2.GetR()) {
            VECAdd(&pos1, &pos2, param_2);
            VECScale(param_2, param_2, 0.5f);
            return true;
        }
        return false;
    }

    return false;
}

inline bool cM3d_Cross_CpsCyl_Check(cM3dGCps const& cps, cM3dGCyl const& cyl, Vec& pos1, Vec& pos2, Vec* param_4) {
    f32 dist = VECDistance(&pos1, &pos2);
    if (dist < cps.GetR()) {
        VECAdd(&pos1, &pos2, param_4);
        VECScale(param_4, param_4, 0.5f);
        return true;
    }
    return false;
}

/* 8024FF10-802506D4       .text cM3d_Cross_CpsCyl__FRC8cM3dGCpsRC8cM3dGCylP3Vec */
bool cM3d_Cross_CpsCyl(const cM3dGCps& cps, const cM3dGCyl& cyl, Vec* param_2) {
    cM3dGLin line;

    if (cM3d_Cross_CylPnt(&cyl, cps.GetEndP())) {
        *param_2 = *cps.GetEndP();
        return true;
    }

    if (cM3d_Cross_CylPnt(&cyl, cps.GetStartP())) {
        *param_2 = *cps.GetStartP();
        return true;
    }

    *line.GetStartP() = *cyl.GetCP();
    *line.GetEndP() = *cyl.GetCP();
    line.GetEndP()->y += cyl.GetH();
    Vec vec;
    f32 tmp;

    if (cM3d_Len3dSqPntAndSegLine(&cps, line.GetEndP(), &vec, &tmp)) {
        f32 dist = VECDistance(line.GetEndP(), &vec);
        if (dist < cps.GetR()) {
            VECAdd(line.GetEndP(), &vec, param_2);
            VECScale(param_2, param_2, 0.5f);
            *param_2 = *line.GetEndP();
            return true;
        }
    }

    if (cM3d_Len3dSqPntAndSegLine(&cps, line.GetStartP(), &vec, &tmp)) {
        f32 dist = VECDistance(line.GetStartP(), &vec);
        if (dist < cps.GetR()) {
            VECAdd(line.GetStartP(), &vec, param_2);
            VECScale(param_2, param_2, 0.5f);
            return true;
        }
    }

    f32 f1, f2;
    int iVar2 = cM3d_Check_LinLin(&cps, &line, &f1, &f2);

    if (iVar2 == 1) {
        cM3dGSph sph;
        f32 tmp2;
        sph.SetR(cps.GetR());
        sph.SetC(*cps.GetStartP());
        return cM3d_Cross_CylSph(&cyl, &sph, param_2, &tmp2);
    } else if (iVar2 == 2) {
        if (f1 >= 0.0f && f1 <= 1.0f && f2 >= 0.0f && f2 <= 1.0f) {
            Vec pos1, pos2;
            cps.CalcPos(&pos1, f1);
            line.CalcPos(&pos2, f2);
            if (VECDistance(&pos1, &pos2) < cps.GetR() + cyl.GetR()) {
                VECAdd(&pos1, &pos2, param_2);
                VECScale(param_2, param_2, 0.5f);
                return true;
            }
        }
    } else if (iVar2 == 3) {
        Vec pos1, pos2;
        if (f1 < 0.0f) {
            pos1 = cps.GetStart();
            if (f2 < 0.0f) {
                pos2 = line.GetStart();
                return cM3d_Cross_CpsCyl_Check(cps, cyl, pos1, pos2, param_2);
            }
            if (f2 > 1.0f) {
                pos2 = line.GetEnd();
                return cM3d_Cross_CpsCyl_Check(cps, cyl, pos1, pos2, param_2);
            }
            line.CalcPos(&pos2, f2);
        } else if (f1 > 1.0f) {
            pos1 = cps.GetEnd();
            if (f2 < 0.0f) {
                pos2 = line.GetStart();
                return cM3d_Cross_CpsCyl_Check(cps, cyl, pos1, pos2, param_2);
            }
            if (f2 > 1.0f) {
                pos2 = line.GetEnd();
                return cM3d_Cross_CpsCyl_Check(cps, cyl, pos1, pos2, param_2);
            }
            line.CalcPos(&pos2, f2);
        } else {
            cps.CalcPos(&pos1, f1);
            if (f2 < 0.0f) {
                pos2 = line.GetStart();
                return cM3d_Cross_CpsCyl_Check(cps, cyl, pos1, pos2, param_2);
            }
            if (f2 > 1.0f) {
                pos2 = line.GetEnd();
                return cM3d_Cross_CpsCyl_Check(cps, cyl, pos1, pos2, param_2);
            }
            line.CalcPos(&pos2, f2);
        }

        if (VECDistance(&pos1, &pos2) < cps.GetR() + cyl.GetR()) {
            VECAdd(&pos1, &pos2, param_2);
            VECScale(param_2, param_2, 0.5f);
            return true;
        }
        return false;
    }

    return false;
}

/* 802506D4-80250840       .text cM3d_Cross_CpsSph_CrossPos__FRC8cM3dGCpsRC8cM3dGSphRC3VecP3Vec */
void cM3d_Cross_CpsSph_CrossPos(const cM3dGCps& param_1, const cM3dGSph& param_2, const Vec& param_3, Vec* param_4) {
    Vec aVStack_70;
    Vec VStack_7c;
    int iVar5 = cM3d_Cross_LinSph_CrossPos(param_2, param_1, &aVStack_70, &VStack_7c);
    if (iVar5 == 1) {
        *param_4 = aVStack_70;
    } else if (iVar5 == 2) {
        f32 dVar8 = VECSquareDistance(&aVStack_70, param_1.GetStartP());
        f32 dVar9 = VECSquareDistance(&VStack_7c, param_1.GetStartP());
        if (dVar8 < dVar9) {
            *param_4 = aVStack_70;
        } else {
            *param_4 = VStack_7c;
        }
    } else {
        f32 dVar8 = param_1.GetR() + param_2.GetR();
        *param_4 = param_3;
        if (cM3d_IsZero(dVar8)) {
            *param_4 = param_3;
        }
        Vec auStack_88;
        VECSubtract(&param_3, param_2.GetCP(), &auStack_88);
        VECScale(&auStack_88, &auStack_88, param_1.GetR() / dVar8);
        VECAdd(param_4, &auStack_88, param_4);
    }
}

/* 80250840-802509B0       .text cM3d_Cross_CpsSph__FRC8cM3dGCpsRC8cM3dGSphP3Vec */
bool cM3d_Cross_CpsSph(const cM3dGCps& param_1, const cM3dGSph& param_2, Vec* param_3) {
    f32 local_38 = VECDistance(param_1.GetStartP(), param_2.GetCP());
    if (local_38 < param_1.GetR() + param_2.GetR()) {
        cM3d_Cross_CpsSph_CrossPos(param_1, param_2, *param_1.GetStartP(), param_3);
        return true;
    }
    local_38 = VECDistance(param_1.GetEndP(), param_2.GetCP());
    if (local_38 < param_1.GetR() + param_2.GetR()) {
        cM3d_Cross_CpsSph_CrossPos(param_1, param_2, *param_1.GetEndP(), param_3);
        return true;
    }
    Vec auStack_34;
    if (cM3d_Len3dSqPntAndSegLine(&param_1, param_2.GetCP(), &auStack_34, &local_38) != 0) {
        if (std::sqrtf(local_38) < param_1.GetR() + param_2.GetR()) {
            cM3d_Cross_CpsSph_CrossPos(param_1, param_2, auStack_34, param_3);
            return true;
        }
    }
    return false;
}

/* 802509B0-80250D70       .text cM3d_Cross_TriTri__FRC8cM3dGTriRC8cM3dGTriP3Vec */
bool cM3d_Cross_TriTri(const cM3dGTri& t0, const cM3dGTri& t1, Vec* r5) {
    f32 aVal01 = t0.getPlaneFunc(&t1.mA);
    f32 bVal01 = t0.getPlaneFunc(&t1.mB);
    f32 cVal01 = t0.getPlaneFunc(&t1.mC);
    if ((aVal01 > 0.0f && bVal01 > 0.0f && cVal01 > 0.0f) || (aVal01 < 0.0f && bVal01 < 0.0f && cVal01 < 0.0f)) {
        return false;
    }
    
    f32 aVal10 = t1.getPlaneFunc(&t0.mA);
    f32 bVal10 = t1.getPlaneFunc(&t0.mB);
    f32 cVal10 = t1.getPlaneFunc(&t0.mC);
    if ((aVal10 > 0.0f && bVal10 > 0.0f && cVal10 > 0.0f) || (aVal10 < 0.0f && bVal10 < 0.0f && cVal10 < 0.0f)) {
        return false;
    }
    
    cM3dGLin lin;
    lin.SetStartEnd(t1.mA, t1.mB);
    if (t0.cross(&lin, r5, false, false)) { return true; }
    lin.SetStartEnd(t1.mB, t1.mC);
    if (t0.cross(&lin, r5, false, false)) { return true; }
    lin.SetStartEnd(t1.mA, t1.mB);
    if (t0.cross(&lin, r5, false, false)) { return true; }
    lin.SetStartEnd(t0.mA, t0.mB);
    if (t1.cross(&lin, r5, false, false)) { return true; }
    lin.SetStartEnd(t0.mB, t0.mC);
    if (t1.cross(&lin, r5, false, false)) { return true; }
    lin.SetStartEnd(t0.mA, t0.mB);
    if (t1.cross(&lin, r5, false, false)) { return true; }
    return false;
}

inline f32 cM3d_2LinCenter(cM3dGLin const& pLinA, f32 pLinAF, cM3dGLin const& pLinB, f32 pLinBF, Vec* pVecOut) {
    Vec tmp, tmp2;
    pLinA.CalcPos(&tmp, pLinAF);
    pLinB.CalcPos(&tmp2, pLinBF);
    VECAdd(&tmp, &tmp2, pVecOut);
    VECScale(pVecOut, pVecOut, 0.5f);
    return VECDistance(&tmp, &tmp2);
}

/* 80250D70-80251280       .text cM3d_Cross_CpsTri__FRC8cM3dGCps8cM3dGTriP3Vec */
bool cM3d_Cross_CpsTri(const cM3dGCps& cps, cM3dGTri tri, Vec* param_2) {
    cM3dGSph sph;
    sph.SetC(*cps.GetStartP());
    sph.SetR(cps.GetR());
    if (cM3d_Cross_SphTri(&sph, &tri, param_2)) {
        return true;
    }

    sph.SetC(*cps.GetEndP());
    sph.SetR(cps.GetR());
    if (cM3d_Cross_SphTri(&sph, &tri, param_2)) {
        return true;
    }

    if (!cM3d_Cross_LinPla(&cps, &tri, param_2, true, true)) {
        return false;
    }

    if (cM3d_Cross_LinTri_Easy(&tri, param_2)) {
        return true;
    }

    cM3dGLin line;
    f32 f1, f2;

    line.SetStartEnd(tri.mA, tri.mB);
    if (cM3d_Check_LinLin(&cps, &line, &f1, &f2) >= 2
        && f1 > 0.0f && f1 < 1.0f && f2 > 0.0f && f2 < 1.0f
        && cM3d_2LinCenter(cps, f1, line, f2, param_2) < cps.GetR())
    {
        return true;
    }

    line.SetStartEnd(tri.mB, tri.mC);
    if (cM3d_Check_LinLin(&cps, &line, &f1, &f2) >= 2
        && f1 > 0.0f && f1 < 1.0f && f2 > 0.0f && f2 < 1.0f
        && cM3d_2LinCenter(cps, f1, line, f2, param_2) < cps.GetR())
    {
        return true;
    }

    line.SetStartEnd(tri.mC, tri.mA);
    if (cM3d_Check_LinLin(&cps, &line, &f1, &f2) >= 2
        && f1 > 0.0f && f1 < 1.0f && f2 > 0.0f && f2 < 1.0f
        && cM3d_2LinCenter(cps, f1, line, f2, param_2) < cps.GetR())
    {
        return true;
    }

    return false;
}

/* 80251280-802514EC       .text cM3d_NearPos_Cps__FRC8cM3dGCpsRC3VecP3Vec */
bool cM3d_NearPos_Cps(const cM3dGCps& cps, const Vec& param_2, Vec* param_3) {
    Vec sp3C;
    f32 sp14;
    if (cM3d_Len3dSqPntAndSegLine(&cps, &param_2, &sp3C, &sp14)) {
        sp14 = std::sqrtf(sp14);
        Vec tmp;
        VECSubtract(&param_2, &sp3C, &tmp);
        VECScale(&tmp, &tmp, cps.GetR() / sp14);
        VECAdd(&sp3C, &tmp, param_3);
        return true;
    }
    f32 f31 = VECSquareDistance(cps.GetStartP(), &param_2);
    f32 f1 = VECSquareDistance(cps.GetEndP(), &param_2);
    if (f31 < f1) {
        f31 = std::sqrtf(f31);
        Vec tmp;
        VECSubtract(cps.GetStartP(), &param_2, &tmp);
        VECScale(&tmp, &tmp, cps.GetR() / f31);
        VECAdd(cps.GetStartP(), &tmp, param_3);
    } else {
        f1 = std::sqrtf(f1);
        Vec tmp;
        VECSubtract(cps.GetEndP(), &param_2, &tmp);
        VECScale(&tmp, &tmp, cps.GetR() / f1);
        VECAdd(cps.GetEndP(), &tmp, param_3);
    }
    return true;
}

/* 802514EC-80251560       .text cM3d_CalcVecAngle__FRC3VecPsPs */
void cM3d_CalcVecAngle(const Vec& vec, s16* a, s16* b) {
    *a = -cM_atan2s(-vec.z * vec.y, 1.0f);
    *b = cM_atan2s(-vec.x * vec.y, 1.0f);
}

/* 80251560-80251634       .text cM3d_CalcVecZAngle__FRC3VecP5csXyz */
void cM3d_CalcVecZAngle(const Vec& param_0, csXyz* param_1) {
    param_1->x = -cM_atan2s(param_0.y, std::sqrtf(param_0.x * param_0.x + param_0.z * param_0.z));
    param_1->y = cM_atan2s(param_0.x, param_0.z);
    param_1->z = 0;
}

/* 80251634-8025172C       .text cM3d_UpMtx_Base__FRC3VecRC3VecPA4_f */
int cM3d_UpMtx_Base(const Vec& param_0, const Vec& param_1, Mtx m) {
    if (cM3d_IsZero(VECMag(&param_1))) {
        MTXIdentity(m);
        return 0;
    }

    Vec sp3C;
    Vec sp48;
    VECNormalize(&param_1, &sp48);
    VECCrossProduct(&param_0, &sp48, &sp3C);

    if (cM3d_IsZero(VECMag(&sp3C))) {
        sp3C.x = 1.0f;
        sp3C.y = 0.0f;
        sp3C.z = 0.0f;
    }

    f32 var_f31 = VECDotProduct(&param_0, &sp48);
    if (var_f31 > 1.0f) {
        var_f31 = 1.0f;
    } else if (var_f31 < -1.0f) {
        var_f31 = -1.0f;
    }

    f32 var_f30 = (float)acos(var_f31);
    // Bug? Calls the C_MTX func instead of the PSMTX func in the release version.
    C_MTXRotAxisRad(m, &sp3C, var_f30);
    return 1;
}

#ifdef DEBUG
static Vec base_y = {0.0f, 1.0f, 0.0f};

bool cM3d_UpMtx(const Vec& param_1, Mtx param_2) {
    return cM3d_UpMtx_Base(base_y, param_1, param_2);
}
#endif

/* 8025172C-80251758       .text cM3d_PlaneCrossLineProcWork__FfffffffPfPf */
void cM3d_PlaneCrossLineProcWork(f32 v0, f32 v1, f32 v2, f32 v3, f32 v4, f32 v5, f32 v6, f32* p0, f32* p1) {
    *p0 = (v1 * v6 - v3 * v5) / v4;
    *p1 = (v2 * v5 - v0 * v6) / v4;
}

/* 80251758-802518F0       .text cM3d_2PlaneCrossLine__FRC8cM3dGPlaRC8cM3dGPlaP8cM3dGLin */
int cM3d_2PlaneCrossLine(const cM3dGPla& pPlaneA, const cM3dGPla& pPlaneB, cM3dGLin* pLinOut) {
    Vec tmp;
    VECCrossProduct(pPlaneA.GetNP(), pPlaneB.GetNP(), &tmp);
    if (cM3d_IsZero(tmp.x) && cM3d_IsZero(tmp.y) && cM3d_IsZero(tmp.z)) {
        return 0;
    } else {
        f32 absTX = std::fabsf(tmp.x);
        f32 absTY = std::fabsf(tmp.y);
        f32 absTZ = std::fabsf(tmp.z);
        if (absTX >= absTY && absTX >= absTZ) {
            cM3d_PlaneCrossLineProcWork(pPlaneA.GetNP()->y, pPlaneA.GetNP()->z, pPlaneB.GetNP()->y,
                                        pPlaneB.GetNP()->z, tmp.x, pPlaneA.GetD(), pPlaneB.GetD(),
                                        &pLinOut->GetStartP()->y, &pLinOut->GetStartP()->z);
            pLinOut->GetStartP()->x = 0.0f;
        } else if (absTY >= absTX && absTY >= absTZ) {
            cM3d_PlaneCrossLineProcWork(pPlaneA.GetNP()->z, pPlaneA.GetNP()->x, pPlaneB.GetNP()->z,
                                        pPlaneB.GetNP()->x, tmp.y, pPlaneA.GetD(), pPlaneB.GetD(),
                                        &pLinOut->GetStartP()->z, &pLinOut->GetStartP()->x);
            pLinOut->GetStartP()->y = 0.0f;
        } else {
            cM3d_PlaneCrossLineProcWork(pPlaneA.GetNP()->x, pPlaneA.GetNP()->y, pPlaneB.GetNP()->x,
                                        pPlaneB.GetNP()->y, tmp.z, pPlaneA.GetD(), pPlaneB.GetD(),
                                        &pLinOut->GetStartP()->x, &pLinOut->GetStartP()->y);
            pLinOut->GetStartP()->z = 0.0f;
        }
        f32 scale = VECMag(pLinOut->GetStartP());
        VECScale(&tmp, &tmp, scale);
        VECAdd(pLinOut->GetStartP(), &tmp, pLinOut->GetEndP());
        return 1;
    }
}

/* 802518F0-80251A10       .text cM3d_3PlaneCrossPos__FRC8cM3dGPlaRC8cM3dGPlaRC8cM3dGPlaP3Vec */
BOOL cM3d_3PlaneCrossPos(const cM3dGPla& p0, const cM3dGPla& p1, const cM3dGPla& p2, Vec* pDst) {
    cM3dGLin lin;
    if (!cM3d_2PlaneCrossLine(p0, p1, &lin))
        return false;

    Vec& start = lin.GetStart();
    Vec& end = lin.GetEnd();
    if (!cM3d_CrossInfLineVsInfPlane_proc(p2.getPlaneFunc(&start), p2.getPlaneFunc(&end), &start, &end, pDst))
        return false;

    return true;
}

/* 80251A10-80251AE4       .text cM3d_lineVsPosSuisenCross__FPC8cM3dGLinPC3VecP3Vec */
f32 cM3d_lineVsPosSuisenCross(const cM3dGLin* g_lin, const Vec* pt, Vec* dst) {
    Vec lin;

    g_lin->CalcVec(&lin);
    f32 len = VECSquareMag(&lin);
    if (cM3d_IsZero(len)) {
        *dst = *pt;
    }

    Vec p0_v;
    VECSubtract(pt, g_lin->GetStartP(), &p0_v);
    f32 dot = VECDotProduct(&p0_v, &lin);
    f32 v = dot / len;

    Vec ret;
    VECScale(&lin, &ret, v);
    VECAdd(&ret, g_lin->GetStartP(), dst);
    return v;
}

/* 80251AE4-80251BC0       .text cM3d_lineVsPosSuisenCross__FRC3VecRC3VecRC3VecP3Vec */
f32 cM3d_lineVsPosSuisenCross(const Vec& a, const Vec& b, const Vec& pt, Vec* dst) {
    Vec lin;
    VECSubtract(&b, &a, &lin);

    f32 len = VECSquareMag(&lin);
    if (cM3d_IsZero(len)) {
        *dst = pt;
        return 0.0f;
    }

    Vec p0_v;
    VECSubtract(&pt, &a, &p0_v);
    f32 dot = VECDotProduct(&p0_v, &lin);
    f32 v = dot / len;
    Vec ret;
    VECScale(&lin, &ret, v);
    VECAdd(&ret, &a, dst);
    return v;
}

/* 80251BC0-80251C44       .text cM3d_2PlaneLinePosNearPos__FRC8cM3dGPlaRC8cM3dGPlaPC3VecP3Vec */
int cM3d_2PlaneLinePosNearPos(const cM3dGPla& p0, const cM3dGPla& p1, const Vec* line, Vec* pDst) {
    cM3dGLin lin;
    if (cM3d_2PlaneCrossLine(p0, p1, &lin) == 0)
        return false;

    cM3d_lineVsPosSuisenCross(&lin, line, pDst);
    return true;
}

/* 80251C44-80251CC4       .text cM3d_CrawVec__FRC3VecRC3VecP3Vec */
void cM3d_CrawVec(const Vec& v0, const Vec& v1, Vec* pDst) {
    Vec tmp;
    f32 sq = std::fabsf(v1.x * v0.x + v1.y * v0.y + v1.z * v0.z);
    VECScale(&v0, &tmp, sq);
    VECAdd(&tmp, &v1, pDst);
}
