#include <math.h>

#include "cm_terrain_private.h"

qboolean CM_PositionTestInTerrainCollide(
    const traceWork_t *traceWork,
    const patchCollide_t *patchCollide)
{
    if (traceWork->isPoint != 0) {
        return 0;
    }

    const facet_t *facet = patchCollide->facets;
    for (int32_t facetIndex = 0; facetIndex < patchCollide->numFacets;
         ++facetIndex, ++facet) {
        const patchPlane_t *plane =
            &patchCollide->planes[facet->surfacePlane];

        vec3_t planeNormal = {plane->normal[0], plane->normal[1],
                              plane->normal[2]};
        float planeDist = plane->dist;
        vec3_t testPoint;

        if (traceWork->sphere.use != 0) {
            planeDist += traceWork->sphere.radius;

            const float sphereOffset =
                ((planeNormal[0] * traceWork->sphere.offset[0]) +
                 (planeNormal[1] * traceWork->sphere.offset[1])) +
                (planeNormal[2] * traceWork->sphere.offset[2]);

            if (sphereOffset > 0.0f) {
                testPoint[0] =
                    traceWork->start[0] - traceWork->sphere.offset[0];
                testPoint[1] =
                    traceWork->start[1] - traceWork->sphere.offset[1];
                testPoint[2] =
                    traceWork->start[2] - traceWork->sphere.offset[2];
            } else {
                testPoint[0] =
                    traceWork->start[0] + traceWork->sphere.offset[0];
                testPoint[1] =
                    traceWork->start[1] + traceWork->sphere.offset[1];
                testPoint[2] =
                    traceWork->start[2] + traceWork->sphere.offset[2];
            }
        } else {
            const float *offset = traceWork->offsets[plane->signbits];
            const float planeOffset =
                ((offset[0] * planeNormal[0]) +
                 (offset[1] * planeNormal[1])) +
                (offset[2] * planeNormal[2]);

            planeDist -= planeOffset;
            testPoint[0] = traceWork->start[0];
            testPoint[1] = traceWork->start[1];
            testPoint[2] = traceWork->start[2];
        }

        /* 0x8051188..0x80511aa: the root distance is compared against zero
         * in the 80-bit register chain with no intermediate float store. */
        if (!((((planeNormal[0] * testPoint[0]) +
                (planeNormal[1] * testPoint[1])) +
               (planeNormal[2] * testPoint[2])) -
                  planeDist >
              0.0f)) {
            int32_t childIndex;

            for (childIndex = 0; childIndex < facet->numBorders;
                 ++childIndex) {
                plane =
                    &patchCollide->planes[facet->borderPlanes[childIndex]];

                if (facet->borderInward[childIndex] == 0) {
                    planeNormal[0] = plane->normal[0];
                    planeNormal[1] = plane->normal[1];
                    planeNormal[2] = plane->normal[2];
                    planeDist = plane->dist;
                } else {
                    planeNormal[0] = -plane->normal[0];
                    planeNormal[1] = -plane->normal[1];
                    planeNormal[2] = -plane->normal[2];
                    planeDist = -plane->dist;
                }

                if (traceWork->sphere.use != 0) {
                    planeDist += traceWork->sphere.radius;

                    const float sphereOffset =
                        ((planeNormal[0] * traceWork->sphere.offset[0]) +
                         (planeNormal[1] * traceWork->sphere.offset[1])) +
                        (planeNormal[2] * traceWork->sphere.offset[2]);

                    if (sphereOffset > 0.0f) {
                        testPoint[0] =
                            traceWork->start[0] -
                            traceWork->sphere.offset[0];
                        testPoint[1] =
                            traceWork->start[1] -
                            traceWork->sphere.offset[1];
                        testPoint[2] =
                            traceWork->start[2] -
                            traceWork->sphere.offset[2];
                    } else {
                        testPoint[0] =
                            traceWork->start[0] +
                            traceWork->sphere.offset[0];
                        testPoint[1] =
                            traceWork->start[1] +
                            traceWork->sphere.offset[1];
                        testPoint[2] =
                            traceWork->start[2] +
                            traceWork->sphere.offset[2];
                    }
                } else {
                    const float *offset =
                        traceWork->offsets[plane->signbits];
                    const float planeOffset =
                        ((offset[0] * planeNormal[0]) +
                         (offset[1] * planeNormal[1])) +
                        (offset[2] * planeNormal[2]);

                    planeDist += fabsf(planeOffset);
                    testPoint[0] = traceWork->start[0];
                    testPoint[1] = traceWork->start[1];
                    testPoint[2] = traceWork->start[2];
                }

                /* 0x80513a3..0x80513c5: the child distance is compared
                 * against zero in the 80-bit register chain with no
                 * intermediate float store. */
                if ((((planeNormal[0] * testPoint[0]) +
                      (planeNormal[1] * testPoint[1])) +
                     (planeNormal[2] * testPoint[2])) -
                        planeDist >
                    0.0f) {
                    break;
                }
            }

            if (childIndex >= facet->numBorders) {
                return 1;
            }
        }
    }

    return 0;
}
