text: ///////////////////////////////////////////////////////////////////////////////////
  /// OpenGL Mathematics (glm.g-truc.net)
  ///
  /// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net)
  /// Permission is hereby granted, free of charge, to any person obtaining a copy
  /// of this software and associated documentation files (the "Software"), to deal
  /// in the Software without restriction, including without limitation the rights
  /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  /// copies of the Software, and to permit persons to whom the Software is
  /// furnished to do so, subject to the following conditions:
  /// 
  /// The above copyright notice and this permission notice shall be included in
  /// all copies or substantial portions of the Software.
  /// 
  /// Restrictions:
  ///		By making use of the Software for military purposes, you choose to make
  ///		a Bunny unhappy.
  /// 
  /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  /// THE SOFTWARE.
  ///
  /// @ref gtx_simd_mat4
  /// @file glm/gtx/simd_mat4.inl
  /// @date 2009-05-07 / 2011-06-07
  /// @author Christophe Riccio
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  
  namespace glm{
  namespace detail{
  
  GLM_FUNC_QUALIFIER length_t fmat4x4SIMD::length() const
  {
  	return 4;
  }
  
  //////////////////////////////////////
  // Accesses
  
  GLM_FUNC_QUALIFIER fvec4SIMD & fmat4x4SIMD::operator[]
  (
  	length_t i
  )
  {
  	assert(i < this->length());
  
  	return this->Data[i];
  }
  
  GLM_FUNC_QUALIFIER fvec4SIMD const & fmat4x4SIMD::operator[]
  (
  	length_t i
  ) const
  {
  	assert(i < this->length());
  
  	return this->Data[i];
  }
  
  //////////////////////////////////////////////////////////////
  // Constructors
  
  #if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
  	GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD()
  	{
  #		ifndef GLM_FORCE_NO_CTOR_INIT
  			this->Data[0] = fvec4SIMD(1, 0, 0, 0);
  			this->Data[1] = fvec4SIMD(0, 1, 0, 0);
  			this->Data[2] = fvec4SIMD(0, 0, 1, 0);
  			this->Data[3] = fvec4SIMD(0, 0, 0, 1);
  #		endif
  	}
  #	endif//!GLM_HAS_DEFAULTED_FUNCTIONS
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD(float const & s)
  {
  	this->Data[0] = fvec4SIMD(s, 0, 0, 0);
  	this->Data[1] = fvec4SIMD(0, s, 0, 0);
  	this->Data[2] = fvec4SIMD(0, 0, s, 0);
  	this->Data[3] = fvec4SIMD(0, 0, 0, s);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
  (
  	float const & x0, float const & y0, float const & z0, float const & w0,
  	float const & x1, float const & y1, float const & z1, float const & w1,
  	float const & x2, float const & y2, float const & z2, float const & w2,
  	float const & x3, float const & y3, float const & z3, float const & w3
  )
  {
  	this->Data[0] = fvec4SIMD(x0, y0, z0, w0);
  	this->Data[1] = fvec4SIMD(x1, y1, z1, w1);
  	this->Data[2] = fvec4SIMD(x2, y2, z2, w2);
  	this->Data[3] = fvec4SIMD(x3, y3, z3, w3);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
  (
  	fvec4SIMD const & v0,
  	fvec4SIMD const & v1,
  	fvec4SIMD const & v2,
  	fvec4SIMD const & v3
  )
  {
  	this->Data[0] = v0;
  	this->Data[1] = v1;
  	this->Data[2] = v2;
  	this->Data[3] = v3;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
  (
  	mat4 const & m
  )
  {
  	this->Data[0] = fvec4SIMD(m[0]);
  	this->Data[1] = fvec4SIMD(m[1]);
  	this->Data[2] = fvec4SIMD(m[2]);
  	this->Data[3] = fvec4SIMD(m[3]);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
  (
  	__m128 const in[4]
  )
  {
  	this->Data[0] = in[0];
  	this->Data[1] = in[1];
  	this->Data[2] = in[2];
  	this->Data[3] = in[3];
  }
  
  //////////////////////////////////////////////////////////////
  // mat4 operators
  
  #if !GLM_HAS_DEFAULTED_FUNCTIONS
  	GLM_FUNC_QUALIFIER fmat4x4SIMD& fmat4x4SIMD::operator=
  	(
  		fmat4x4SIMD const & m
  	)
  	{
  		this->Data[0] = m[0];
  		this->Data[1] = m[1];
  		this->Data[2] = m[2];
  		this->Data[3] = m[3];
  		return *this;
  	}
  #endif//!GLM_HAS_DEFAULTED_FUNCTIONS
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator+= 
  (
  	fmat4x4SIMD const & m
  )
  {
  	this->Data[0].Data = _mm_add_ps(this->Data[0].Data, m[0].Data);
  	this->Data[1].Data = _mm_add_ps(this->Data[1].Data, m[1].Data);
  	this->Data[2].Data = _mm_add_ps(this->Data[2].Data, m[2].Data);
  	this->Data[3].Data = _mm_add_ps(this->Data[3].Data, m[3].Data);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator-= 
  (
  	fmat4x4SIMD const & m
  )
  {
  	this->Data[0].Data = _mm_sub_ps(this->Data[0].Data, m[0].Data);
  	this->Data[1].Data = _mm_sub_ps(this->Data[1].Data, m[1].Data);
  	this->Data[2].Data = _mm_sub_ps(this->Data[2].Data, m[2].Data);
  	this->Data[3].Data = _mm_sub_ps(this->Data[3].Data, m[3].Data);
  
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator*= 
  (
  	fmat4x4SIMD const & m
  )
  {
  	sse_mul_ps(&this->Data[0].Data, &m.Data[0].Data, &this->Data[0].Data);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator/= 
  (
  	fmat4x4SIMD const & m
  )
  {
  	__m128 Inv[4];
  	sse_inverse_ps(&m.Data[0].Data, Inv);
  	sse_mul_ps(&this->Data[0].Data, Inv, &this->Data[0].Data);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator+= 
  (
  	float const & s
  )
  {
  	__m128 Operand = _mm_set_ps1(s);
  	this->Data[0].Data = _mm_add_ps(this->Data[0].Data, Operand);
  	this->Data[1].Data = _mm_add_ps(this->Data[1].Data, Operand);
  	this->Data[2].Data = _mm_add_ps(this->Data[2].Data, Operand);
  	this->Data[3].Data = _mm_add_ps(this->Data[3].Data, Operand);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator-= 
  (
  	float const & s
  )
  {
  	__m128 Operand = _mm_set_ps1(s);
  	this->Data[0].Data = _mm_sub_ps(this->Data[0].Data, Operand);
  	this->Data[1].Data = _mm_sub_ps(this->Data[1].Data, Operand);
  	this->Data[2].Data = _mm_sub_ps(this->Data[2].Data, Operand);
  	this->Data[3].Data = _mm_sub_ps(this->Data[3].Data, Operand);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator*= 
  (
  	float const & s
  )
  {
  	__m128 Operand = _mm_set_ps1(s);
  	this->Data[0].Data = _mm_mul_ps(this->Data[0].Data, Operand);
  	this->Data[1].Data = _mm_mul_ps(this->Data[1].Data, Operand);
  	this->Data[2].Data = _mm_mul_ps(this->Data[2].Data, Operand);
  	this->Data[3].Data = _mm_mul_ps(this->Data[3].Data, Operand);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator/= 
  (
  	float const & s
  )
  {
  	__m128 Operand = _mm_div_ps(one, _mm_set_ps1(s));
  	this->Data[0].Data = _mm_mul_ps(this->Data[0].Data, Operand);
  	this->Data[1].Data = _mm_mul_ps(this->Data[1].Data, Operand);
  	this->Data[2].Data = _mm_mul_ps(this->Data[2].Data, Operand);
  	this->Data[3].Data = _mm_mul_ps(this->Data[3].Data, Operand);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator++ ()
  {
  	this->Data[0].Data = _mm_add_ps(this->Data[0].Data, one);
  	this->Data[1].Data = _mm_add_ps(this->Data[1].Data, one);
  	this->Data[2].Data = _mm_add_ps(this->Data[2].Data, one);
  	this->Data[3].Data = _mm_add_ps(this->Data[3].Data, one);
  	return *this;
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator-- ()
  {
  	this->Data[0].Data = _mm_sub_ps(this->Data[0].Data, one);
  	this->Data[1].Data = _mm_sub_ps(this->Data[1].Data, one);
  	this->Data[2].Data = _mm_sub_ps(this->Data[2].Data, one);
  	this->Data[3].Data = _mm_sub_ps(this->Data[3].Data, one);
  	return *this;
  }
  
  
  //////////////////////////////////////////////////////////////
  // Binary operators
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator+
  (
  	const fmat4x4SIMD &m,
  	float const & s
  )
  {
  	return detail::fmat4x4SIMD
  	(
  		m[0] + s,
  		m[1] + s,
  		m[2] + s,
  		m[3] + s
  	);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator+
  (
  	float const & s,
  	const fmat4x4SIMD &m
  )
  {
  	return detail::fmat4x4SIMD
  	(
  		m[0] + s,
  		m[1] + s,
  		m[2] + s,
  		m[3] + s
  	);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator+
  (
      const fmat4x4SIMD &m1,
      const fmat4x4SIMD &m2
  )
  {
      return detail::fmat4x4SIMD
      (
          m1[0] + m2[0],
          m1[1] + m2[1],
          m1[2] + m2[2],
          m1[3] + m2[3]
      );
  }
  
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator-
  (
      const fmat4x4SIMD &m,
      float const & s
  )
  {
      return detail::fmat4x4SIMD
      (
          m[0] - s,
          m[1] - s,
          m[2] - s,
          m[3] - s
      );
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator-
  (
      float const & s,
      const fmat4x4SIMD &m
  )
  {
      return detail::fmat4x4SIMD
      (
          s - m[0],
          s - m[1],
          s - m[2],
          s - m[3]
      );
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator-
  (
      const fmat4x4SIMD &m1,
      const fmat4x4SIMD &m2
  )
  {
      return detail::fmat4x4SIMD
      (
          m1[0] - m2[0],
          m1[1] - m2[1],
          m1[2] - m2[2],
          m1[3] - m2[3]
      );
  }
  
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator*
  (
      const fmat4x4SIMD &m,
      float const & s
  )
  {
      return detail::fmat4x4SIMD
      (
          m[0] * s,
          m[1] * s,
          m[2] * s,
          m[3] * s
      );
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator*
  (
      float const & s,
      const fmat4x4SIMD &m
  )
  {
      return detail::fmat4x4SIMD
      (
          m[0] * s,
          m[1] * s,
          m[2] * s,
          m[3] * s
      );
  }
  
  GLM_FUNC_QUALIFIER fvec4SIMD operator*
  (
      const fmat4x4SIMD &m,
      fvec4SIMD const & v
  )
  {
      return sse_mul_ps(&m.Data[0].Data, v.Data);
  }
  
  GLM_FUNC_QUALIFIER fvec4SIMD operator*
  (
      fvec4SIMD const & v,
      const fmat4x4SIMD &m
  )
  {
      return sse_mul_ps(v.Data, &m.Data[0].Data);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator*
  (
      const fmat4x4SIMD &m1,
      const fmat4x4SIMD &m2
  )
  {
      fmat4x4SIMD result;
      sse_mul_ps(&m1.Data[0].Data, &m2.Data[0].Data, &result.Data[0].Data);
      
      return result;
  }
      
  
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator/
  (
      const fmat4x4SIMD &m,
      float const & s
  )
  {
      return detail::fmat4x4SIMD
      (
          m[0] / s,
          m[1] / s,
          m[2] / s,
          m[3] / s
      );
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator/
  (
      float const & s,
      const fmat4x4SIMD &m
  )
  {
      return detail::fmat4x4SIMD
      (
          s / m[0],
          s / m[1],
          s / m[2],
          s / m[3]
      );
  }
  
  GLM_FUNC_QUALIFIER detail::fmat4x4SIMD inverse(detail::fmat4x4SIMD const & m)
  {
  	detail::fmat4x4SIMD result;
  	detail::sse_inverse_ps(&m[0].Data, &result[0].Data);
  	return result;
  }
  
  GLM_FUNC_QUALIFIER fvec4SIMD operator/
  (
  	const fmat4x4SIMD & m,
  	fvec4SIMD const & v
  )
  {
  	return inverse(m) * v;
  }
  
  GLM_FUNC_QUALIFIER fvec4SIMD operator/
  (
  	fvec4SIMD const & v,
  	const fmat4x4SIMD &m
  )
  {
  	return v * inverse(m);
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD operator/
  (
  	const fmat4x4SIMD &m1,
  	const fmat4x4SIMD &m2
  )
  {
  	__m128 result[4];
  	__m128 inv[4];
  
  	sse_inverse_ps(&m2.Data[0].Data, inv);
  	sse_mul_ps(&m1.Data[0].Data, inv, result);
  
  	return fmat4x4SIMD(result);
  }
  
  
  //////////////////////////////////////////////////////////////
  // Unary constant operators
  GLM_FUNC_QUALIFIER fmat4x4SIMD const operator-
  (
      fmat4x4SIMD const & m
  )
  {
      return detail::fmat4x4SIMD
      (
          -m[0],
          -m[1],
          -m[2],
          -m[3]
      );
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD const operator--
  (
      fmat4x4SIMD const & m,
      int
  )
  {
      return detail::fmat4x4SIMD
      (
          m[0] - 1.0f,
          m[1] - 1.0f,
          m[2] - 1.0f,
          m[3] - 1.0f
      );
  }
  
  GLM_FUNC_QUALIFIER fmat4x4SIMD const operator++
  (
      fmat4x4SIMD const & m,
      int
  )
  {
      return detail::fmat4x4SIMD
      (
          m[0] + 1.0f,
          m[1] + 1.0f,
          m[2] + 1.0f,
          m[3] + 1.0f
      );
  }
  
  }//namespace detail
  
  GLM_FUNC_QUALIFIER mat4 mat4_cast
  (
  	detail::fmat4x4SIMD const & x
  )
  {
  	GLM_ALIGN(16) mat4 Result;
  	_mm_store_ps(&Result[0][0], x.Data[0].Data);
  	_mm_store_ps(&Result[1][0], x.Data[1].Data);
  	_mm_store_ps(&Result[2][0], x.Data[2].Data);
  	_mm_store_ps(&Result[3][0], x.Data[3].Data);
  	return Result;
  }
  
  GLM_FUNC_QUALIFIER detail::fmat4x4SIMD matrixCompMult
  (
  	detail::fmat4x4SIMD const & x,
  	detail::fmat4x4SIMD const & y
  )
  {
  	detail::fmat4x4SIMD result;
  	result[0] = x[0] * y[0];
  	result[1] = x[1] * y[1];
  	result[2] = x[2] * y[2];
  	result[3] = x[3] * y[3];
  	return result;
  }
  
  GLM_FUNC_QUALIFIER detail::fmat4x4SIMD outerProduct
  (
  	detail::fvec4SIMD const & c,
  	detail::fvec4SIMD const & r
  )
  {
  	__m128 Shu0 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(0, 0, 0, 0));
  	__m128 Shu1 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(1, 1, 1, 1));
  	__m128 Shu2 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(2, 2, 2, 2));
  	__m128 Shu3 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(3, 3, 3, 3));
  
  	detail::fmat4x4SIMD result(uninitialize);
  	result[0].Data = _mm_mul_ps(c.Data, Shu0);
  	result[1].Data = _mm_mul_ps(c.Data, Shu1);
  	result[2].Data = _mm_mul_ps(c.Data, Shu2);
  	result[3].Data = _mm_mul_ps(c.Data, Shu3);
  	return result;
  }
  
  GLM_FUNC_QUALIFIER detail::fmat4x4SIMD transpose(detail::fmat4x4SIMD const & m)
  {
  	detail::fmat4x4SIMD result;
  	detail::sse_transpose_ps(&m[0].Data, &result[0].Data);
  	return result;
  }
  
  GLM_FUNC_QUALIFIER float determinant(detail::fmat4x4SIMD const & m)
  {
  	float Result;
  	_mm_store_ss(&Result, detail::sse_det_ps(&m[0].Data));
  	return Result;
  }
  
  }//namespace glm
  