/* SCE CONFIDENTIAL
PLAYSTATION(R)3 Programmer Tool Runtime Library 084.006
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* All Rights Reserved.
*/

#ifndef _BOOLINVEC_H
#define _BOOLINVEC_H

#include <math.h>
#include <altivec.h>

namespace Vectormath {

class floatInVec;

//--------------------------------------------------------------------------------------------------
// boolInVec class
//

class boolInVec
{
    private:
        vec_uint4 mData;

        inline boolInVec(vec_uint4 vec);
    public:
        inline boolInVec() {}

        // matches standard type conversions
        //
        inline boolInVec(floatInVec vec);

        // explicit cast from bool
        //
        explicit inline boolInVec(bool scalar);

#ifdef _VECTORMATH_NO_SCALAR_CAST
        // explicit cast to bool
        // 
        inline bool getAsBool() const;
#else
        // implicit cast to bool
        // 
        inline operator bool() const;
#endif
        
        // get vector data
        // bool value is splatted across all word slots of vector as 0 (false) or -1 (true)
        //
        inline vec_uint4 get128() const;

        // operators
        //
        inline const boolInVec operator ! () const;
        inline boolInVec& operator = (boolInVec vec);
        inline boolInVec& operator &= (boolInVec vec);
        inline boolInVec& operator ^= (boolInVec vec);
        inline boolInVec& operator |= (boolInVec vec);

        // friend functions
        //
        friend inline const boolInVec operator == (boolInVec vec0, boolInVec vec1);
        friend inline const boolInVec operator != (boolInVec vec0, boolInVec vec1);
        friend inline const boolInVec operator < (floatInVec vec0, floatInVec vec1);
        friend inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1);
        friend inline const boolInVec operator > (floatInVec vec0, floatInVec vec1);
        friend inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1);
        friend inline const boolInVec operator == (floatInVec vec0, floatInVec vec1);
        friend inline const boolInVec operator != (floatInVec vec0, floatInVec vec1);
        friend inline const boolInVec operator & (boolInVec vec0, boolInVec vec1);
        friend inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1);
        friend inline const boolInVec operator | (boolInVec vec0, boolInVec vec1);
        friend inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1);
};

//--------------------------------------------------------------------------------------------------
// boolInVec functions
//

// operators
//
inline const boolInVec operator == (boolInVec vec0, boolInVec vec1);
inline const boolInVec operator != (boolInVec vec0, boolInVec vec1);
inline const boolInVec operator & (boolInVec vec0, boolInVec vec1);
inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1);
inline const boolInVec operator | (boolInVec vec0, boolInVec vec1);

// select between vec0 and vec1 using boolInVec.
// false selects vec0, true selects vec1
//
inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1);

} // namespace Vectormath

//--------------------------------------------------------------------------------------------------
// boolInVec implementation
//

#include "floatInVec.h"

namespace Vectormath {

inline
boolInVec::boolInVec(vec_uint4 vec)
{
    mData = vec;
}

inline
boolInVec::boolInVec(floatInVec vec)
{
    *this = (vec != floatInVec(0.0f));
}

inline
boolInVec::boolInVec(bool scalar)
{
#ifdef __GNUC__
    if (__builtin_constant_p(scalar))
    {
        const unsigned int mask = -(int)scalar;
        mData = (vec_uint4){mask, mask, mask, mask};
    }
    else
#endif
    {
        unsigned int mask = -(int)scalar;
        vec_uint4 vec = vec_ld(0, &mask);
        mData = vec_splat(vec_perm(vec, vec, vec_lvsl(0, &mask)), 0);
    }
}

#ifdef _VECTORMATH_NO_SCALAR_CAST
inline
bool
boolInVec::getAsBool() const
#else
inline
boolInVec::operator bool() const
#endif
{
    return vec_all_gt(mData, (vec_uint4)(0));
}

inline
vec_uint4
boolInVec::get128() const
{
    return mData;
}

inline
const boolInVec
boolInVec::operator ! () const
{
    return boolInVec(vec_nor(mData, mData));
}

inline
boolInVec&
boolInVec::operator = (boolInVec vec)
{
    mData = vec.mData;
    return *this;
}

inline
boolInVec&
boolInVec::operator &= (boolInVec vec)
{
    *this = *this & vec;
    return *this;
}

inline
boolInVec&
boolInVec::operator ^= (boolInVec vec)
{
    *this = *this ^ vec;
    return *this;
}

inline
boolInVec&
boolInVec::operator |= (boolInVec vec)
{
    *this = *this | vec;
    return *this;
}

inline
const boolInVec
operator == (boolInVec vec0, boolInVec vec1)
{
    return boolInVec((vec_uint4)vec_cmpeq(vec0.get128(), vec1.get128()));
}

inline
const boolInVec
operator != (boolInVec vec0, boolInVec vec1)
{
    return !(vec0 == vec1);
}
    
inline
const boolInVec
operator & (boolInVec vec0, boolInVec vec1)
{
    return boolInVec(vec_and(vec0.get128(), vec1.get128()));
}

inline
const boolInVec
operator | (boolInVec vec0, boolInVec vec1)
{
    return boolInVec(vec_or(vec0.get128(), vec1.get128()));
}

inline
const boolInVec
operator ^ (boolInVec vec0, boolInVec vec1)
{
    return boolInVec(vec_xor(vec0.get128(), vec1.get128()));
}

inline
const boolInVec
select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1)
{
    return boolInVec(vec_sel(vec0.get128(), vec1.get128(), select_vec1.get128()));
}
 
} // namespace Vectormath

#endif // boolInVec_h
