/** 
 * @file llsimdtypes.h
 * @brief Declaration of basic SIMD math related types
 *
 * $LicenseInfo:firstyear=2010&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef LL_SIMD_TYPES_H
#define LL_SIMD_TYPES_H

#ifndef LL_SIMD_MATH_H
#error "Please include llmath.h before this file."
#endif

typedef __m128	LLQuad;


#if LL_WINDOWS
#pragma warning(push)
#pragma warning( disable : 4800 3 ) // Disable warning about casting int to bool for this class.
#if defined(_MSC_VER) && (_MSC_VER < 1500)
// VC++ 2005 is missing these intrinsics
// __forceinline is MSVC specific and attempts to override compiler inlining judgment. This is so
// even in debug builds this call is a NOP.
__forceinline const __m128 _mm_castsi128_ps( const __m128i a ) { return reinterpret_cast<const __m128&>(a); }
__forceinline const __m128i _mm_castps_si128( const __m128 a ) { return reinterpret_cast<const __m128i&>(a); }
#endif // _MSC_VER

#endif // LL_WINDOWS

class LLBool32
{
public:
	inline LLBool32() {}
	inline LLBool32(int rhs) : m_bool(rhs) {}
	inline LLBool32(unsigned int rhs) : m_bool(rhs) {}
	inline LLBool32(bool rhs) { m_bool = static_cast<const int>(rhs); }
	inline LLBool32& operator= (bool rhs) { m_bool = (int)rhs; return *this; }
	inline bool operator== (bool rhs) const { return static_cast<const bool&>(m_bool) == rhs; }
	inline bool operator!= (bool rhs) const { return !operator==(rhs); }
	inline operator bool() const { return static_cast<const bool&>(m_bool); }

private:
	int m_bool;
};

#if LL_WINDOWS
#pragma warning(pop)
#endif

class LLSimdScalar
{
public:
	inline LLSimdScalar() {}
	inline LLSimdScalar(LLQuad q) 
	{ 
		mQ = q; 
	}

	inline LLSimdScalar(F32 f) 
	{ 
		mQ = _mm_set_ss(f); 
	}

	static inline const LLSimdScalar& getZero()
	{
		extern const LLQuad F_ZERO_4A;
		return reinterpret_cast<const LLSimdScalar&>(F_ZERO_4A);
	}

	inline F32 getF32() const;

	inline LLBool32 isApproximatelyEqual(const LLSimdScalar& rhs, F32 tolerance = F_APPROXIMATELY_ZERO) const;

	inline LLSimdScalar getAbs() const;

	inline void setMax( const LLSimdScalar& a, const LLSimdScalar& b );
	
	inline void setMin( const LLSimdScalar& a, const LLSimdScalar& b );

	inline LLSimdScalar& operator=(F32 rhs);

	inline LLSimdScalar& operator+=(const LLSimdScalar& rhs);

	inline LLSimdScalar& operator-=(const LLSimdScalar& rhs);

	inline LLSimdScalar& operator*=(const LLSimdScalar& rhs);

	inline LLSimdScalar& operator/=(const LLSimdScalar& rhs);

	inline operator LLQuad() const
	{ 
		return mQ; 
	}
	
	inline const LLQuad& getQuad() const 
	{ 
		return mQ; 
	}

private:
	LLQuad mQ;
};

#endif //LL_SIMD_TYPES_H