#include "coduo_x87emu.h" /* defines EMULATE_X87; x87 shim when it is 1 */

#include "cm_patch_private.h"

void CM_TracePointThroughPatchCollide(traceWork_t *traceWork,
                                      const coduo_patch_collide_t *patchCollide)
{
    for (int32_t facetIndex = 0;
         facetIndex < (int32_t)patchCollide->facetCount; ++facetIndex) {
        const coduo_patch_collision_facet_t *facet =
            &patchCollide->facets[facetIndex];
        const coduo_patch_collision_plane_t *surfacePlane =
            &facet->surfacePlane;

#if EMULATE_X87
        /* x87 (DLL 0x08055595): each plane distance is one 80-bit chain — three
         * products, two adds and the -dist — rounded once at its float slot
         * (fmul;fmul;faddp;fmul;faddp;fsub dist;fstp). The comparisons are
         * fucompp against fldz / the float epsilons, and fall through on
         * unordered operands, which the negated `!(a >= b)` forms preserve. */
        const float endDistance = x87f_store_f32(x87f_sub(
            x87f_add(x87f_add(x87f_mul(x87f_load_f32(traceWork->end[0]),
                                       x87f_load_f32(surfacePlane->normal[0])),
                              x87f_mul(x87f_load_f32(traceWork->end[1]),
                                       x87f_load_f32(surfacePlane->normal[1]))),
                     x87f_mul(x87f_load_f32(traceWork->end[2]),
                              x87f_load_f32(surfacePlane->normal[2]))),
            x87f_load_f32(surfacePlane->dist)));
#else
        const float endDistance =
            ((traceWork->end[0] * surfacePlane->normal[0]) +
             (traceWork->end[1] * surfacePlane->normal[1])) +
            (traceWork->end[2] * surfacePlane->normal[2]) -
            surfacePlane->dist;
#endif

        /*
         * The original x87 comparisons fall through on unordered operands; the
         * negated forms below preserve that branch behavior.
         */
        if (!(endDistance >= 0.0f)) {
#if EMULATE_X87
            const float startDistance = x87f_store_f32(x87f_sub(
                x87f_add(
                    x87f_add(x87f_mul(x87f_load_f32(traceWork->start[0]),
                                      x87f_load_f32(surfacePlane->normal[0])),
                             x87f_mul(x87f_load_f32(traceWork->start[1]),
                                      x87f_load_f32(surfacePlane->normal[1]))),
                    x87f_mul(x87f_load_f32(traceWork->start[2]),
                             x87f_load_f32(surfacePlane->normal[2]))),
                x87f_load_f32(surfacePlane->dist)));
#else
            const float startDistance =
                ((traceWork->start[0] * surfacePlane->normal[0]) +
                 (traceWork->start[1] * surfacePlane->normal[1])) +
                (traceWork->start[2] * surfacePlane->normal[2]) -
                surfacePlane->dist;
#endif

            if (!(0.0f >= startDistance)) {
#if EMULATE_X87
                const float enterFraction = x87f_store_f32(x87f_div(
                    x87f_sub(x87f_load_f32(startDistance),
                             x87f_load_f32(CODUO_PATCH_POINT_ENTER_EPSILON)),
                    x87f_sub(x87f_load_f32(startDistance),
                             x87f_load_f32(endDistance))));
#else
                const float enterFraction =
                    (startDistance - CODUO_PATCH_POINT_ENTER_EPSILON) /
                    (startDistance - endDistance);
#endif

                if (!(enterFraction >= traceWork->trace.fraction)) {
#if EMULATE_X87
                    const float hitFraction = x87f_store_f32(x87f_div(
                        x87f_load_f32(startDistance),
                        x87f_sub(x87f_load_f32(startDistance),
                                 x87f_load_f32(endDistance))));
                    const float hitX = x87f_store_f32(x87f_add(
                        x87f_load_f32(traceWork->start[0]),
                        x87f_mul(x87f_load_f32(traceWork->delta[0]),
                                 x87f_load_f32(hitFraction))));
                    const float hitY = x87f_store_f32(x87f_add(
                        x87f_load_f32(traceWork->start[1]),
                        x87f_mul(x87f_load_f32(traceWork->delta[1]),
                                 x87f_load_f32(hitFraction))));
                    const float hitZ = x87f_store_f32(x87f_add(
                        x87f_load_f32(traceWork->start[2]),
                        x87f_mul(x87f_load_f32(traceWork->delta[2]),
                                 x87f_load_f32(hitFraction))));
                    const coduo_patch_collision_plane_t *edgePlane =
                        &facet->edgePlanes[0];

                    const float edge0Distance = x87f_store_f32(x87f_sub(
                        x87f_add(x87f_add(x87f_mul(x87f_load_f32(hitX),
                                                   x87f_load_f32(
                                                       edgePlane->normal[0])),
                                          x87f_mul(x87f_load_f32(hitY),
                                                   x87f_load_f32(
                                                       edgePlane->normal[1]))),
                                 x87f_mul(x87f_load_f32(hitZ),
                                          x87f_load_f32(edgePlane->normal[2]))),
                        x87f_load_f32(edgePlane->dist)));
#else
                    const float hitFraction =
                        startDistance / (startDistance - endDistance);
                    const float hitX =
                        traceWork->start[0] +
                        (traceWork->delta[0] * hitFraction);
                    const float hitY =
                        traceWork->start[1] +
                        (traceWork->delta[1] * hitFraction);
                    const float hitZ =
                        traceWork->start[2] +
                        (traceWork->delta[2] * hitFraction);
                    const coduo_patch_collision_plane_t *edgePlane =
                        &facet->edgePlanes[0];

                    const float edge0Distance =
                        ((hitX * edgePlane->normal[0]) +
                         (hitY * edgePlane->normal[1])) +
                        (hitZ * edgePlane->normal[2]) - edgePlane->dist;
#endif

                    if (!(CODUO_PATCH_BARYCENTRIC_MIN > edge0Distance) &&
                        !(edge0Distance > CODUO_PATCH_BARYCENTRIC_MAX)) {
                        edgePlane = &facet->edgePlanes[1];
#if EMULATE_X87
                        const float edge1Distance = x87f_store_f32(x87f_sub(
                            x87f_add(
                                x87f_add(x87f_mul(x87f_load_f32(hitX),
                                                  x87f_load_f32(
                                                      edgePlane->normal[0])),
                                         x87f_mul(x87f_load_f32(hitY),
                                                  x87f_load_f32(
                                                      edgePlane->normal[1]))),
                                x87f_mul(x87f_load_f32(hitZ),
                                         x87f_load_f32(edgePlane->normal[2]))),
                            x87f_load_f32(edgePlane->dist)));

                        /* edge0Distance + edge1Distance is formed and compared
                         * in 80-bit (fadd; fld max; fucompp) with no store. */
                        if (!(CODUO_PATCH_BARYCENTRIC_MIN > edge1Distance) &&
                            !x87f_lt(
                                x87f_load_f32(CODUO_PATCH_BARYCENTRIC_MAX),
                                x87f_add(x87f_load_f32(edge0Distance),
                                         x87f_load_f32(edge1Distance)))) {
#else
                        const float edge1Distance =
                            ((hitX * edgePlane->normal[0]) +
                             (hitY * edgePlane->normal[1])) +
                            (hitZ * edgePlane->normal[2]) - edgePlane->dist;

                        if (!(CODUO_PATCH_BARYCENTRIC_MIN > edge1Distance) &&
                            !((edge0Distance + edge1Distance) >
                              CODUO_PATCH_BARYCENTRIC_MAX)) {
#endif
                            traceWork->trace.fraction = enterFraction;
                            traceWork->trace.normal[0] =
                                surfacePlane->normal[0];
                            traceWork->trace.normal[1] =
                                surfacePlane->normal[1];
                            traceWork->trace.normal[2] =
                                surfacePlane->normal[2];
                        }
                    }
                }
            }
        }
    }
}
