1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use super::Vec3;
use core::{fmt, ops::*};

/// A 3-dimensional vector mask.
#[derive(Clone, Copy, Default, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct Vec3Mask(pub(crate) u32, pub(crate) u32, pub(crate) u32);

impl Vec3Mask {
    /// Creates a new `Vec3Mask`.
    #[inline]
    pub fn new(x: bool, y: bool, z: bool) -> Self {
        // A SSE2 mask can be any bit pattern but for the `Vec3Mask` implementation of select we
        // expect either 0 or 0xff_ff_ff_ff. This should be a safe assumption as this type can only
        // be created via this function or by `Vec3` methods.
        const MASK: [u32; 2] = [0, 0xff_ff_ff_ff];
        Self(MASK[x as usize], MASK[y as usize], MASK[z as usize])
    }

    /// Returns a bitmask with the lowest three bits set from the elements of `self`.
    ///
    /// A true element results in a `1` bit and a false element in a `0` bit.  Element `x` goes
    /// into the first lowest bit, element `y` into the second, etc.
    #[inline]
    pub fn bitmask(&self) -> u32 {
        // _mm_movemask_ps only checks the most significant bit of the u32 is
        // true, so we replicate that here with the non-SSE2 version.
        (self.0 & 0x1) | (self.1 & 0x1) << 1 | (self.2 & 0x1) << 2
    }

    /// Returns true if any of the elements are true, false otherwise.
    ///
    /// In other words: `x || y || z`.
    #[inline]
    pub fn any(&self) -> bool {
        ((self.0 | self.1 | self.2) & 0x1) != 0
    }

    /// Returns true if all the elements are true, false otherwise.
    ///
    /// In other words: `x && y && z`.
    #[inline]
    pub fn all(&self) -> bool {
        ((self.0 & self.1 & self.2) & 0x1) != 0
    }

    /// Creates a `Vec3` from the elements in `if_true` and `if_false`, selecting which to use for
    /// each element of `self`.
    ///
    /// A true element in the mask uses the corresponding element from `if_true`, and false uses
    /// the element from `if_false`.
    #[inline]
    pub fn select(self, if_true: Vec3, if_false: Vec3) -> Vec3 {
        // We are assuming that the mask values are either 0 or 0xff_ff_ff_ff for the SSE2 and f32
        // to behave the same here.
        Vec3(
            if self.0 != 0 { if_true.0 } else { if_false.0 },
            if self.1 != 0 { if_true.1 } else { if_false.1 },
            if self.2 != 0 { if_true.2 } else { if_false.2 },
        )
    }
}

impl BitAnd for Vec3Mask {
    type Output = Self;
    #[inline]
    fn bitand(self, other: Self) -> Self {
        Self(self.0 & other.0, self.1 & other.1, self.2 & other.2)
    }
}

impl BitAndAssign for Vec3Mask {
    #[inline]
    fn bitand_assign(&mut self, other: Self) {
        self.0 &= other.0;
        self.1 &= other.1;
        self.2 &= other.2;
    }
}

impl BitOr for Vec3Mask {
    type Output = Self;
    #[inline]
    fn bitor(self, other: Self) -> Self {
        Self(self.0 | other.0, self.1 | other.1, self.2 | other.2)
    }
}

impl BitOrAssign for Vec3Mask {
    #[inline]
    fn bitor_assign(&mut self, other: Self) {
        self.0 |= other.0;
        self.1 |= other.1;
        self.2 |= other.2;
    }
}

impl Not for Vec3Mask {
    type Output = Self;
    #[inline]
    fn not(self) -> Self {
        Self(!self.0, !self.1, !self.2)
    }
}

impl fmt::Debug for Vec3Mask {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Vec3Mask({:#x}, {:#x}, {:#x})", self.0, self.1, self.2)
    }
}

impl fmt::Display for Vec3Mask {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let arr = self.as_ref();
        write!(f, "[{}, {}, {}]", arr[0] != 0, arr[1] != 0, arr[2] != 0,)
    }
}

impl From<Vec3Mask> for [u32; 3] {
    #[inline]
    fn from(mask: Vec3Mask) -> Self {
        *mask.as_ref()
    }
}

impl AsRef<[u32; 3]> for Vec3Mask {
    #[inline]
    fn as_ref(&self) -> &[u32; 3] {
        unsafe { &*(self as *const Self as *const [u32; 3]) }
    }
}