#include <math.h>

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

#include "core_math_private.h"

long double RotationToYaw(const vec2_t vector)
{
    float xSquared;
    float scale;
    float degrees;

#if EMULATE_X87
    /* x87-faithful transcription (stock coduo_lnxded 0x08069aa1): xSquared and
     * scale = 2.0f/(x*x + y*y) are float-rounded; each atan2 argument
     * (x*y*scale) and (1.0 - x*x*scale) is formed in 80-bit and rounded to
     * double64; the atan2 return in st(0) is multiplied by 180/pi
     * (0x404ca5dc1a63c1f8) in 80-bit and rounded straight to float (no
     * intermediate double). atan2 is a libm call left native. */
    xSquared =
        x87f_store_f32(x87f_mul(x87f_load_f32(vector[0]), x87f_load_f32(vector[0])));
    scale = x87f_store_f32(x87f_add(
        x87f_load_f32(xSquared),
        x87f_mul(x87f_load_f32(vector[1]), x87f_load_f32(vector[1]))));
    scale = x87f_store_f32(x87f_div(x87f_load_f32(2.0f), x87f_load_f32(scale)));

    {
        const double numerator = x87f_store_f64(x87f_mul(
            x87f_mul(x87f_load_f32(vector[0]), x87f_load_f32(vector[1])),
            x87f_load_f32(scale)));
        const double denominator = x87f_store_f64(
            x87f_sub(x87f_load_f64(1.0),
                     x87f_mul(x87f_load_f32(xSquared), x87f_load_f32(scale))));
        degrees = x87f_store_f32(
            x87f_mul(x87f_load_f64(57.29577951308232),
                     x87f_load_f64(atan2(numerator, denominator))));
    }
#else
    xSquared = vector[0] * vector[0];
    scale = xSquared + (vector[1] * vector[1]);
    scale = 2.0f / scale;

    /* The stock binary multiplies the atan2 return in st(0) directly
     * (0x8069af9..0x8069b06: call/fld m64/fmulp/fstp m32) -- the result is
     * never rounded to double, so no intermediate double variable here. */
    degrees = (float)(57.29577951308232 *
                      atan2((double)(vector[0] * vector[1] * scale),
                            (double)(1.0 - (xSquared * scale))));
#endif

    return (long double)degrees;
}
