#include "cm_terrain_private.h"

qboolean CM_SightTracePointThroughTerrainCollide(
    const traceWork_t *traceWork,
    const patchCollide_t *patchCollide)
{
    float planeFractions[CM_PATCH_MAX_PLANES];
    qboolean planeSides[CM_PATCH_MAX_PLANES];

    if (cm_playerCurveClip->integer == 0 || traceWork->isPoint == 0) {
        return 1;
    }

    const patchPlane_t *plane = patchCollide->planes;
    for (int32_t planeIndex = 0; planeIndex < patchCollide->numPlanes;
         ++planeIndex, ++plane) {
        const float *offset = traceWork->offsets[plane->signbits];
        const float planeOffset =
            ((offset[0] * plane->normal[0]) +
             (offset[1] * plane->normal[1])) +
            (offset[2] * plane->normal[2]);
        const float startDistance =
            (((traceWork->start[0] * plane->normal[0]) +
              (traceWork->start[1] * plane->normal[1])) +
             (traceWork->start[2] * plane->normal[2])) -
            plane->dist + planeOffset;
        const float endDistance =
            (((traceWork->end[0] * plane->normal[0]) +
              (traceWork->end[1] * plane->normal[1])) +
             (traceWork->end[2] * plane->normal[2])) -
            plane->dist + planeOffset;

        if (startDistance <= 0.0f) {
            planeSides[planeIndex] = 0;
        } else {
            planeSides[planeIndex] = 1;
        }

        if (startDistance == endDistance) {
            planeFractions[planeIndex] = 99999.0f;
        } else {
            planeFractions[planeIndex] =
                startDistance / (startDistance - endDistance);
            if (planeFractions[planeIndex] <= 0.0f) {
                planeFractions[planeIndex] = 99999.0f;
            }
        }
    }

    const facet_t *facet = patchCollide->facets;
    for (int32_t facetIndex = 0;
         facetIndex < patchCollide->numFacets; ++facetIndex, ++facet) {
        const int32_t rootPlaneIndex = facet->surfacePlane;

        if (planeSides[rootPlaneIndex] == 0) {
            continue;
        }

        const float rootFraction = planeFractions[rootPlaneIndex];
        if (rootFraction < 0.0f) {
            continue;
        }

        int32_t childIndex;
        for (childIndex = 0; childIndex < facet->numBorders;
             ++childIndex) {
            const int32_t childPlaneIndex =
                facet->borderPlanes[childIndex];

            if (planeSides[childPlaneIndex] ==
                facet->borderInward[childIndex]) {
                if (planeFractions[childPlaneIndex] < rootFraction) {
                    break;
                }
            } else if (rootFraction < planeFractions[childPlaneIndex]) {
                break;
            }
        }

        if (childIndex == facet->numBorders) {
            plane = &patchCollide->planes[rootPlaneIndex];

            const float *offset = traceWork->offsets[plane->signbits];
            const float planeOffset =
                ((offset[0] * plane->normal[0]) +
                 (offset[1] * plane->normal[1])) +
                (offset[2] * plane->normal[2]);
            const float startDistance =
                (((traceWork->start[0] * plane->normal[0]) +
                  (traceWork->start[1] * plane->normal[1])) +
                 (traceWork->start[2] * plane->normal[2])) -
                plane->dist + planeOffset;
            const float endDistance =
                (((traceWork->end[0] * plane->normal[0]) +
                  (traceWork->end[1] * plane->normal[1])) +
                 (traceWork->end[2] * plane->normal[2])) -
                plane->dist + planeOffset;

            if (startDistance - endDistance > 0.0f &&
                (startDistance - 0.125f) /
                        (startDistance - endDistance) <
                    1.0f) {
                return 0;
            }
        }
    }

    return 1;
}
