#include "vector.h"
#include "harness/trace.h"
#include <math.h>


#define BR_MAC2(A, B, C, D) ((A) * (B) + (C) * (D))
#define BR_MAC4(A, B, C, D, E, F, G, H) ((A) * (B) + (C) * (D) + (E) * (F) + (G) * (H))

// IDA: void __cdecl BrVector2Copy(br_vector2 *v1, br_vector2 *v2)
void BrVector2Copy(br_vector2* v1, br_vector2* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] = v2->v[0];
    v1->v[1] = v2->v[1];
}

// IDA: void __cdecl BrVector2Set(br_vector2 *v1, br_scalar s1, br_scalar s2)
void BrVector2Set(br_vector2* v1, br_scalar s1, br_scalar s2) {
    LOG_TRACE("(%p, %f, %f)", v1, s1, s2);

    v1->v[0] = s1;
    v1->v[1] = s2;
}

// IDA: void __cdecl BrVector2SetInt(br_vector2 *v1, int i1, int i2)
void BrVector2SetInt(br_vector2* v1, int i1, int i2) {
    LOG_TRACE("(%p, %d, %d)", v1, i1, i2);

    v1->v[0] = BR_SCALAR(i1);
    v1->v[1] = BR_SCALAR(i2);
}

// IDA: void __cdecl BrVector2SetFloat(br_vector2 *v1, float f1, float f2)
void BrVector2SetFloat(br_vector2* v1, float f1, float f2) {
    LOG_TRACE("(%p, %f, %f)", v1, f1, f2);

    v1->v[0] = f1;
    v1->v[1] = f2;
}

// IDA: void __cdecl BrVector2Negate(br_vector2 *v1, br_vector2 *v2)
void BrVector2Negate(br_vector2* v1, br_vector2* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] = -v2->v[0];
    v1->v[1] = -v2->v[1];
}

// IDA: void __cdecl BrVector2Add(br_vector2 *v1, br_vector2 *v2, br_vector2 *v3)
void BrVector2Add(br_vector2* v1, br_vector2* v2, br_vector2* v3) {
    LOG_TRACE("(%p, %p, %p)", v1, v2, v3);

    v1->v[0] = v2->v[0] + v3->v[0];
    v1->v[1] = v2->v[1] + v3->v[1];
}

// IDA: void __cdecl BrVector2Accumulate(br_vector2 *v1, br_vector2 *v2)
void BrVector2Accumulate(br_vector2* v1, br_vector2* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] += v2->v[0];
    v1->v[1] += v2->v[1];
}

// IDA: void __cdecl BrVector2Sub(br_vector2 *v1, br_vector2 *v2, br_vector2 *v3)
void BrVector2Sub(br_vector2* v1, br_vector2* v2, br_vector2* v3) {
    LOG_TRACE("(%p, %p, %p)", v1, v2, v3);

    v1->v[0] = v2->v[0] - v3->v[0];
    v1->v[1] = v2->v[1] - v3->v[1];
}

// IDA: void __cdecl BrVector2Scale(br_vector2 *v1, br_vector2 *v2, br_scalar s)
void BrVector2Scale(br_vector2* v1, br_vector2* v2, br_scalar s) {
    LOG_TRACE("(%p, %p, %f)", v1, v2, s);

    v1->v[0] = v2->v[0] * s;
    v1->v[1] = v2->v[1] * s;
}

// IDA: void __cdecl BrVector2InvScale(br_vector2 *v1, br_vector2 *v2, br_scalar s)
void BrVector2InvScale(br_vector2* v1, br_vector2* v2, br_scalar s) {
    LOG_TRACE("(%p, %p, %f)", v1, v2, s);

    v1->v[0] = v2->v[0] / s;
    v1->v[1] = v2->v[1] / s;
}

// IDA: br_scalar __cdecl BrVector2Dot(br_vector2 *v1, br_vector2 *v2)
br_scalar BrVector2Dot(br_vector2* v1, br_vector2* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    return BR_MAC2(v1->v[0], v2->v[0], v1->v[1], v2->v[1]);
}

// IDA: br_scalar __cdecl BrVector2Length(br_vector2 *v1)
br_scalar BrVector2Length(br_vector2* v1) {
    LOG_TRACE("(%p)", v1);

    return sqrtf(BR_MAC2(v1->v[0], v1->v[0], v1->v[1], v1->v[1]));
}

// IDA: br_scalar __cdecl BrVector2LengthSquared(br_vector2 *v1)
br_scalar BrVector2LengthSquared(br_vector2* v1) {
    LOG_TRACE("(%p)", v1);

    return BR_MAC2(v1->v[0], v1->v[0], v1->v[1], v1->v[1]);
}

// IDA: void __cdecl BrVector3Copy(br_vector3 *v1, br_vector3 *v2)
void BrVector3Copy(br_vector3* v1, br_vector3* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] = v2->v[0];
    v1->v[1] = v2->v[1];
    v1->v[2] = v2->v[2];
}

// IDA: void __cdecl BrVector3Set(br_vector3 *v1, br_scalar s1, br_scalar s2, br_scalar s3)
void BrVector3Set(br_vector3* v1, br_scalar s1, br_scalar s2, br_scalar s3) {
    LOG_TRACE("(%p, %f, %f, %f)", v1, s1, s2, s3);

    v1->v[0] = s1;
    v1->v[1] = s2;
    v1->v[2] = s3;
}

// IDA: void __cdecl BrVector3SetInt(br_vector3 *v1, int i1, int i2, int i3)
void BrVector3SetInt(br_vector3* v1, int i1, int i2, int i3) {
    LOG_TRACE("(%p, %d, %d, %d)", v1, i1, i2, i3);

    v1->v[0] = BR_SCALAR(i1);
    v1->v[1] = BR_SCALAR(i2);
    v1->v[2] = BR_SCALAR(i3);
}

// IDA: void __cdecl BrVector3SetFloat(br_vector3 *v1, float f1, float f2, float f3)
void BrVector3SetFloat(br_vector3* v1, float f1, float f2, float f3) {
    LOG_TRACE8("(%p, %f, %f, %f)", v1, f1, f2, f3);

    v1->v[0] = BR_SCALAR(f1);
    v1->v[1] = BR_SCALAR(f2);
    v1->v[2] = BR_SCALAR(f3);
}

// IDA: void __cdecl BrVector3Negate(br_vector3 *v1, br_vector3 *v2)
void BrVector3Negate(br_vector3* v1, br_vector3* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] = -v2->v[0];
    v1->v[1] = -v2->v[1];
    v1->v[2] = -v2->v[2];
}

// IDA: void __cdecl BrVector3Add(br_vector3 *v1, br_vector3 *v2, br_vector3 *v3)
void BrVector3Add(br_vector3* v1, br_vector3* v2, br_vector3* v3) {
    LOG_TRACE("(%p, %p, %p)", v1, v2, v3);

    v1->v[0] = v2->v[0] + v3->v[0];
    v1->v[1] = v2->v[1] + v3->v[1];
    v1->v[2] = v2->v[2] + v3->v[2];
}

// IDA: void __cdecl BrVector3Accumulate(br_vector3 *v1, br_vector3 *v2)
void BrVector3Accumulate(br_vector3* v1, br_vector3* v2) {
    LOG_TRACE10("(%p, %p)", v1, v2);

    v1->v[0] += v2->v[0];
    v1->v[1] += v2->v[1];
    v1->v[2] += v2->v[2];
}

// IDA: void __cdecl BrVector3Sub(br_vector3 *v1, br_vector3 *v2, br_vector3 *v3)
void BrVector3Sub(br_vector3* v1, br_vector3* v2, br_vector3* v3) {
    LOG_TRACE("(%p, %p, %p)", v1, v2, v3);

    v1->v[0] = v2->v[0] - v3->v[0];
    v1->v[1] = v2->v[1] - v3->v[1];
    v1->v[2] = v2->v[2] - v3->v[2];
}

// IDA: void __cdecl BrVector3Scale(br_vector3 *v1, br_vector3 *v2, br_scalar s)
void BrVector3Scale(br_vector3* v1, br_vector3* v2, br_scalar s) {
    LOG_TRACE("(%p, %p, %f)", v1, v2, s);

    v1->v[0] = v2->v[0] * s;
    v1->v[1] = v2->v[1] * s;
    v1->v[2] = v2->v[2] * s;
}

// IDA: void __cdecl BrVector3InvScale(br_vector3 *v1, br_vector3 *v2, br_scalar s)
void BrVector3InvScale(br_vector3* v1, br_vector3* v2, br_scalar s) {
    LOG_TRACE("(%p, %p, %f)", v1, v2, s);

    v1->v[0] = v2->v[0] / s;
    v1->v[1] = v2->v[1] / s;
    v1->v[2] = v2->v[2] / s;
}

// IDA: br_scalar __cdecl BrVector3Dot(br_vector3 *v1, br_vector3 *v2)
br_scalar BrVector3Dot(br_vector3* v1, br_vector3* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    return BR_MAC3(v1->v[0], v2->v[0], v1->v[1], v2->v[1], v1->v[2], v2->v[2]);
}

// IDA: void __cdecl BrVector3Cross(br_vector3 *v1, br_vector3 *v2, br_vector3 *v3)
void BrVector3Cross(br_vector3* v1, br_vector3* v2, br_vector3* v3) {
    LOG_TRACE("(%p, %p, %p)", v1, v2, v3);

    v1->v[0] = v2->v[1] * v3->v[2] - v2->v[2] * v3->v[1];
    v1->v[1] = v2->v[2] * v3->v[0] - v2->v[0] * v3->v[2];
    v1->v[2] = v2->v[0] * v3->v[1] - v2->v[1] * v3->v[0];
}

// IDA: br_scalar __cdecl BrVector3Length(br_vector3 *v1)
br_scalar BrVector3Length(br_vector3* v1) {
    LOG_TRACE("(%p)", v1);

    return sqrtf(BR_MAC3(v1->v[0], v1->v[0], v1->v[1], v1->v[1], v1->v[2], v1->v[2]));
}

// IDA: br_scalar __cdecl BrVector3LengthSquared(br_vector3 *v1)
br_scalar BrVector3LengthSquared(br_vector3* v1) {
    LOG_TRACE("(%p)", v1);

    return BR_MAC3(v1->v[0], v1->v[0], v1->v[1], v1->v[1], v1->v[2], v1->v[2]);
}

// IDA: void __cdecl BrVector3Normalise(br_vector3 *v1, br_vector3 *v2)
void BrVector3Normalise(br_vector3* v1, br_vector3* v2) {
    br_scalar scale;
    LOG_TRACE10("(%p, %p)", v1, v2);

    scale = BR_LENGTH3(v2->v[0], v2->v[1], v2->v[2]);

    if (scale > BR_SCALAR_EPSILON * 2) {
        v1->v[0] = v2->v[0] / scale;
        v1->v[1] = v2->v[1] / scale;
        v1->v[2] = v2->v[2] / scale;

    } else {
        v1->v[0] = BR_SCALAR(1.0);
        v1->v[1] = BR_SCALAR(0.0);
        v1->v[2] = BR_SCALAR(0.0);
    }
}

// IDA: void __cdecl BrVector3NormaliseLP(br_vector3 *v1, br_vector3 *v2)
void BrVector3NormaliseLP(br_vector3* v1, br_vector3* v2) {
    br_scalar scale;
    LOG_TRACE("(%p, %p)", v1, v2);

    scale = 1.f / sqrtf(BR_MAC3(v2->v[0], v2->v[0], v2->v[1], v2->v[1], v2->v[2], v2->v[2]));
    if (scale != 0.f) {
        v1->v[0] = v2->v[0] * scale;
        v1->v[1] = v2->v[1] * scale;
        v1->v[2] = v2->v[2] * scale;
    }
}

// IDA: br_scalar __cdecl BrVector4Dot(br_vector4 *v1, br_vector4 *v2)
br_scalar BrVector4Dot(br_vector4* v1, br_vector4* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    return BR_MAC4(v1->v[0], v2->v[0], v1->v[1], v2->v[1], v1->v[2], v2->v[2], v1->v[3], v2->v[3]);
}

// IDA: void __cdecl BrVector4Copy(br_vector4 *v1, br_vector4 *v2)
void BrVector4Copy(br_vector4* v1, br_vector4* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] = v2->v[0];
    v1->v[1] = v2->v[1];
    v1->v[2] = v2->v[2];
    v1->v[3] = v2->v[3];
}

// IDA: br_scalar __usercall BrFVector2Dot@<ST0>(br_fvector2 *v1@<EAX>, br_vector2 *v2@<EDX>)
br_scalar BrFVector2Dot(br_fvector2* v1, br_vector2* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    return BR_MAC2(v1->v[0], v2->v[0], v1->v[1], v2->v[1]);
}

// IDA: void __usercall BrFVector3Copy(br_fvector3 *v1@<EAX>, br_vector3 *v2@<EDX>)
void BrFVector3Copy(br_fvector3* v1, br_vector3* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    v1->v[0] = v2->v[0];
    v1->v[1] = v2->v[1];
    v1->v[2] = v2->v[2];
}

// IDA: void __usercall BrVector3ScaleF(br_vector3 *v1@<EAX>, br_fvector3 *v2@<EDX>, br_scalar s)
void BrVector3ScaleF(br_vector3* v1, br_fvector3* v2, br_scalar s) {
    LOG_TRACE("(%p, %p, %f)", v1, v2, s);

    v1->v[0] = v2->v[0] * s;
    v1->v[1] = v2->v[1] * s;
    v1->v[2] = v2->v[2] * s;
}

// IDA: br_scalar __usercall BrFVector3Dot@<ST0>(br_fvector3 *v1@<EAX>, br_vector3 *v2@<EDX>)
br_scalar BrFVector3Dot(br_fvector3* v1, br_vector3* v2) {
    LOG_TRACE("(%p, %p)", v1, v2);

    return BR_MAC3(v1->v[0], v2->v[0], v1->v[1], v2->v[1], v1->v[2], v2->v[2]);
}

// IDA: void __usercall BrFVector3Normalise(br_fvector3 *v1@<EAX>, br_vector3 *v2@<EDX>)
void BrFVector3Normalise(br_fvector3* v1, br_vector3* v2) {
    br_scalar scale;
    LOG_TRACE("(%p, %p)", v1, v2);

    scale = sqrtf(BR_MAC3(v2->v[0], v2->v[0], v2->v[1], v2->v[1], v2->v[2], v2->v[2]));
    if (scale != 0.f) {
        scale = 1.f / scale;
        v1->v[0] = v2->v[0] * scale;
        v1->v[1] = v2->v[1] * scale;
        v1->v[2] = v2->v[2] * scale;
    } else {
        v1->v[0] = 1.f;
        v1->v[1] = 0.f;
        v1->v[2] = 0.f;
    }
}

// IDA: void __usercall BrFVector3NormaliseLP(br_fvector3 *v1@<EAX>, br_vector3 *v2@<EDX>)
void BrFVector3NormaliseLP(br_fvector3* v1, br_vector3* v2) {
    br_scalar scale;
    LOG_TRACE("(%p, %p)", v1, v2);

    scale = 1.f / sqrtf(BR_MAC3(v2->v[0], v2->v[0], v2->v[1], v2->v[1], v2->v[2], v2->v[2]));
    v1->v[0] = v2->v[0] * scale;
    v1->v[1] = v2->v[1] * scale;
    v1->v[2] = v2->v[2] * scale;
}

// IDA: void __cdecl BrVector2Normalise(br_vector2 *v1, br_vector2 *v2)
void BrVector2Normalise(br_vector2* v1, br_vector2* v2) {
    br_scalar scale;
    LOG_TRACE("(%p, %p)", v1, v2);

    scale = sqrtf(BR_MAC2(v2->v[0], v2->v[0], v2->v[1], v2->v[1]));
    if (scale > 2.3841858e-7f) {
        scale = 1.f / scale;
        v1->v[0] = v2->v[0] * scale;
        v1->v[1] = v2->v[1] * scale;

    } else {
        v1->v[0] = 1.f;
        v1->v[1] = 0.f;
    }
}
