// (c) Electronic Arts. All Rights Reserved.
//#BLOCK
// (c) Electronic Arts. All Rights Reserved.


class UnitTestSoa4Vector4 :
    public UnitTest
{
public:

    UnitTestSoa4Vector4();
    virtual ~UnitTestSoa4Vector4();
    void Test();

    union TestUnion
    {
        unsigned int u32[4];
        float f32[4];
        ::rw::math::vpu::VectorIntrinsic v;
    };

    ::rw::math::vpu::VectorIntrinsic Set(float);
    ::rw::math::vpu::VectorIntrinsic Set(float, float, float, float);
    ::rw::math::vpu::VectorIntrinsic Set(uint32_t);
    ::rw::math::vpu::VectorIntrinsic Set(uint32_t, uint32_t, uint32_t, uint32_t);

    ::rw::math::vpu::Soa4Vector4 mZero;
    ::rw::math::vpu::Soa4Vector4 mOne;
    ::rw::math::vpu::Soa4Vector4 mTwo;
    ::rw::math::vpu::Soa4Vector4 mNegOne;
    ::rw::math::vpu::Soa4Vector4 mNaN;
    ::rw::math::vpu::Soa4Vector4 mInf;
    ::rw::math::vpu::Soa4Vector4 mMixedNaN;
    ::rw::math::vpu::Soa4Vector4 mMixedInf;

    // mA, mB, and mC are "well behaved"
    ::rw::math::vpu::Soa4Vector4 mA;
    ::rw::math::vpu::Soa4Vector4 mB;
    ::rw::math::vpu::Soa4Vector4 mC;

    ::rw::math::vpu::Soa4MaskScalar CreateSoa4MaskScalar( bool a, bool b, bool c, bool d )
    {
        ::rw::math::vpu::detail::VectorIntrinsicUnion vu;
        
        vu.scalarUInt[0] = a ? 0xFFFFFFFFUL : 0;
        vu.scalarUInt[1] = b ? 0xFFFFFFFFUL : 0;
        vu.scalarUInt[2] = c ? 0xFFFFFFFFUL : 0;
        vu.scalarUInt[3] = d ? 0xFFFFFFFFUL : 0;

        return ::rw::math::vpu::Soa4MaskScalar( vu.vector );
    }

    ::rw::math::vpu::Soa4Float CreateSoa4Float(float x, float y, float z, float w)
    {
        ::rw::math::vpu::detail::VectorIntrinsicUnion vu;
        vu.scalarFloat[0] = x;
        vu.scalarFloat[1] = y;
        vu.scalarFloat[2] = z;
        vu.scalarFloat[3] = w;
        return ::rw::math::vpu::Soa4Float(vu.vector);
    }

    bool IsEqual(::rw::math::vpu::Vector4::InParam a, ::rw::math::vpu::Vector4::InParam b)
    {
        return ( a.X().GetFloat() == b.X().GetFloat() ) && 
            ( a.Y().GetFloat() == b.Y().GetFloat() ) && 
            ( a.Z().GetFloat() == b.Z().GetFloat() ) && 
            ( a.W().GetFloat() == b.W().GetFloat() );
    }

    bool IsEqual(::rw::math::vpu::Soa4Float::InParam a, ::rw::math::vpu::Soa4Float::InParam b)
    {
        return !memcmp( &a.mV, &b.mV, sizeof(::rw::math::vpu::VectorIntrinsic) );
    }

    bool IsEqual(::rw::math::vpu::Soa4Vector4::InParam a, ::rw::math::vpu::Soa4Vector4::InParam b)
    {
        return( IsEqual( a.x, b.x ) && IsEqual( a.y, b.y ) && IsEqual( a.z, b.z ) && IsEqual( a.w, b.w ) );
    }

    bool IsEqual(::rw::math::vpu::Soa4MaskScalar::InParam a, ::rw::math::vpu::Soa4MaskScalar::InParam b)
    {
        ::rw::math::vpu::detail::VectorIntrinsicUnion va, vb;
        va.vector = a.mV;
        vb.vector = b.mV;

        return( va.scalarUInt[0] == vb.scalarUInt[0] &&
            va.scalarUInt[1] == vb.scalarUInt[1] &&
            va.scalarUInt[2] == vb.scalarUInt[2] &&
            va.scalarUInt[3] == vb.scalarUInt[3] );
    }


    bool IsEqual(::rw::math::vpu::Soa4Mask4::InParam a, ::rw::math::vpu::Soa4Mask4::InParam b)
    {
        return( IsEqual( a.x, b.x ) && IsEqual( a.y, b.y ) && IsEqual( a.z, b.z ) );
    }

    bool IsEqualBitwise( ::rw::math::vpu::VectorIntrinsicInParam v0, ::rw::math::vpu::VectorIntrinsicInParam v1 )
    {
        ::rw::math::vpu::detail::VectorIntrinsicUnion v0u, v1u;
        v0u.vector = v0;
        v1u.vector = v1;
        return( 
                v0u.scalarUInt[0] == v1u.scalarUInt[0] &&
                v0u.scalarUInt[1] == v1u.scalarUInt[1] &&
                v0u.scalarUInt[2] == v1u.scalarUInt[2] &&
                v0u.scalarUInt[3] == v1u.scalarUInt[3]
              );
    }

    bool IsEqualWithEpsilon(::rw::math::vpu::Soa4Float::InParam a, ::rw::math::vpu::Soa4Float::InParam b, ::rw::math::vpu::Soa4Float::InParam epsilon)
    {
        ::rw::math::vpu::detail::VectorIntrinsicUnion aU, bU, epsilonU;
        aU.vector = a.mV;
        bU.vector = b.mV;
        epsilonU.vector = epsilon.mV;
        return
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[0], bU.scalarFloat[0], epsilonU.scalarFloat[0] ) &&
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[1], bU.scalarFloat[1], epsilonU.scalarFloat[1] ) &&
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[2], bU.scalarFloat[2], epsilonU.scalarFloat[2] ) &&
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[3], bU.scalarFloat[3], epsilonU.scalarFloat[3] );
    }

    bool IsEqualWithEpsilon(::rw::math::vpu::Soa4Float::InParam a, ::rw::math::vpu::Soa4Float::InParam b, float epsilon = 0.001f)
    {
        ::rw::math::vpu::detail::VectorIntrinsicUnion aU, bU;
        aU.vector = a.mV;
        bU.vector = b.mV;
        return
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[0], bU.scalarFloat[0], epsilon ) &&
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[1], bU.scalarFloat[1], epsilon ) &&
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[2], bU.scalarFloat[2], epsilon ) &&
            UnitTest::IsEqualWithEpsilon( aU.scalarFloat[3], bU.scalarFloat[3], epsilon );
    }

    bool IsEqualWithEpsilon(::rw::math::vpu::Soa4Vector4::InParam a, ::rw::math::vpu::Soa4Vector4::InParam b, float epsilon = 0.001f)
    {
        return IsEqualWithEpsilon( a.x, b.x, epsilon ) && 
            IsEqualWithEpsilon( a.y, b.y, epsilon ) && 
            IsEqualWithEpsilon( a.z, b.z, epsilon ) &&
            IsEqualWithEpsilon( a.w, b.w, epsilon );
    }
    

//#BLOCK

};



