use core::ops::{Add, Mul, Sub};
use glam::{Mat3, Vec3};
use crate::backend::Backend;
use crate::varying::{Gang, Mask, Varying};
#[derive(Clone, Copy)]
pub struct Vec3Wide<S: Backend<f32>>(pub [Varying<f32, S>; 3]);
impl<S: Backend<f32>> From<[Varying<f32, S>; 3]> for Vec3Wide<S> {
#[inline(always)]
fn from(v: [Varying<f32, S>; 3]) -> Self {
Self(v)
}
}
impl<S: Backend<f32>> Vec3Wide<S> {
#[inline(always)]
pub fn dot(self, o: Self) -> Varying<f32, S> {
let [a, b, c] = self.0;
let [x, y, z] = o.0;
a * x + b * y + c * z
}
#[inline(always)]
pub fn length_squared(self) -> Varying<f32, S> {
self.dot(self)
}
#[inline(always)]
pub fn length(self) -> Varying<f32, S> {
self.length_squared().sqrt()
}
#[inline(always)]
pub fn add_scaled(self, dir: Self, t: Varying<f32, S>) -> Self {
self + dir * t
}
#[inline(always)]
pub fn select(self, mask: Mask<f32, S>, other: Self) -> Self {
let [a, b, c] = self.0;
let [x, y, z] = other.0;
Self([a.select(mask, x), b.select(mask, y), c.select(mask, z)])
}
#[inline(always)]
pub fn store(self, out: [&mut [f32]; 3]) {
let [a, b, c] = self.0;
let [ox, oy, oz] = out;
a.store(ox);
b.store(oy);
c.store(oz);
}
#[inline(always)]
pub fn store_partial(self, out: [&mut [f32]; 3]) {
let [a, b, c] = self.0;
let [ox, oy, oz] = out;
a.store_partial(ox);
b.store_partial(oy);
c.store_partial(oz);
}
}
impl<S: Backend<f32>> Add for Vec3Wide<S> {
type Output = Self;
#[inline(always)]
fn add(self, o: Self) -> Self {
let [a, b, c] = self.0;
let [x, y, z] = o.0;
Self([a + x, b + y, c + z])
}
}
impl<S: Backend<f32>> Sub for Vec3Wide<S> {
type Output = Self;
#[inline(always)]
fn sub(self, o: Self) -> Self {
let [a, b, c] = self.0;
let [x, y, z] = o.0;
Self([a - x, b - y, c - z])
}
}
impl<S: Backend<f32>> Mul<Varying<f32, S>> for Vec3Wide<S> {
type Output = Self;
#[inline(always)]
fn mul(self, t: Varying<f32, S>) -> Self {
let [a, b, c] = self.0;
Self([a * t, b * t, c * t])
}
}
impl<S: Backend<f32>> Mul<f32> for Vec3Wide<S> {
type Output = Self;
#[inline(always)]
fn mul(self, t: f32) -> Self {
let [a, b, c] = self.0;
Self([a * t, b * t, c * t])
}
}
#[derive(Clone, Copy)]
pub struct Mat3Wide<S: Backend<f32>>([Varying<f32, S>; 9]);
impl<S: Backend<f32>> Mat3Wide<S> {
#[inline(always)]
pub fn mul_vec3(self, v: Vec3Wide<S>) -> Vec3Wide<S> {
let m = self.0;
let [x, y, z] = v.0;
Vec3Wide([
m[0] * x + m[3] * y + m[6] * z,
m[1] * x + m[4] * y + m[7] * z,
m[2] * x + m[5] * y + m[8] * z,
])
}
#[inline(always)]
pub fn mul_add(self, v: Vec3Wide<S>, t: Vec3Wide<S>) -> Vec3Wide<S> {
self.mul_vec3(v) + t
}
#[inline(always)]
pub fn cols(self) -> [Varying<f32, S>; 9] {
self.0
}
#[inline(always)]
pub fn determinant(self) -> Varying<f32, S> {
let m = self.0;
let c0 = m[1] * m[5] - m[2] * m[4];
let c1 = m[2] * m[3] - m[0] * m[5];
let c2 = m[0] * m[4] - m[1] * m[3];
m[6] * c0 + m[7] * c1 + m[8] * c2
}
#[inline(always)]
pub fn inverse(self) -> Self {
let m = self.0;
let t0x = m[4] * m[8] - m[5] * m[7];
let t0y = m[5] * m[6] - m[3] * m[8];
let t0z = m[3] * m[7] - m[4] * m[6];
let t1x = m[7] * m[2] - m[8] * m[1];
let t1y = m[8] * m[0] - m[6] * m[2];
let t1z = m[6] * m[1] - m[7] * m[0];
let t2x = m[1] * m[5] - m[2] * m[4];
let t2y = m[2] * m[3] - m[0] * m[5];
let t2z = m[0] * m[4] - m[1] * m[3];
let id = (m[6] * t2x + m[7] * t2y + m[8] * t2z).recip();
Self([
t0x * id, t1x * id, t2x * id,
t0y * id, t1y * id, t2y * id,
t0z * id, t1z * id, t2z * id,
])
}
#[inline(always)]
pub fn store(self, out: [&mut [f32]; 9]) {
for (v, o) in self.0.into_iter().zip(out) {
v.store(o);
}
}
#[inline(always)]
pub fn store_partial(self, out: [&mut [f32]; 9]) {
for (v, o) in self.0.into_iter().zip(out) {
v.store_partial(o);
}
}
}
impl<S: Backend<f32>> From<[Varying<f32, S>; 9]> for Mat3Wide<S> {
#[inline(always)]
fn from(v: [Varying<f32, S>; 9]) -> Self {
Self(v)
}
}
#[derive(Clone, Copy)]
pub struct MatWide<S: Backend<f32>, const R: usize, const C: usize>(pub [[Varying<f32, S>; C]; R]);
impl<S: Backend<f32>, const R: usize, const C: usize> From<[[Varying<f32, S>; C]; R]>
for MatWide<S, R, C>
{
#[inline(always)]
fn from(v: [[Varying<f32, S>; C]; R]) -> Self {
Self(v)
}
}
impl<S: Backend<f32>, const R: usize, const C: usize> MatWide<S, R, C> {
#[inline(always)]
pub fn matmul<const N: usize>(self, rhs: MatWide<S, C, N>) -> MatWide<S, R, N> {
MatWide(core::array::from_fn(|i| {
core::array::from_fn(|j| {
let mut acc = self.0[i][0] * rhs.0[0][j];
for k in 1..C {
acc = self.0[i][k].fma(rhs.0[k][j], acc);
}
acc
})
}))
}
#[inline(always)]
pub fn transpose(self) -> MatWide<S, C, R> {
MatWide(core::array::from_fn(|j| core::array::from_fn(|i| self.0[i][j])))
}
#[inline(always)]
pub fn rows(self) -> [[Varying<f32, S>; C]; R] {
self.0
}
#[inline(always)]
pub fn store(self, out: [[&mut [f32]; C]; R]) {
for (row, orow) in self.0.into_iter().zip(out) {
for (v, o) in row.into_iter().zip(orow) {
v.store(o);
}
}
}
#[inline(always)]
pub fn store_partial(self, out: [[&mut [f32]; C]; R]) {
for (row, orow) in self.0.into_iter().zip(out) {
for (v, o) in row.into_iter().zip(orow) {
v.store_partial(o);
}
}
}
}
pub trait GangGlamExt<S: Backend<f32>> {
fn splat_vec3(self, v: Vec3) -> Vec3Wide<S>;
fn gather_vec3(self, s: &[Vec3], fill: f32) -> Vec3Wide<S>;
fn gather_plane(self, s: &[(Vec3, f32)], fill: f32) -> (Vec3Wide<S>, Varying<f32, S>);
fn load_vec3(self, cols: [&[f32]; 3]) -> Vec3Wide<S>;
fn load_partial_vec3(self, cols: [&[f32]; 3], fill: f32) -> Vec3Wide<S>;
fn splat_mat3(self, m: Mat3) -> Mat3Wide<S>;
fn load_mat3(self, cols: [&[f32]; 9]) -> Mat3Wide<S>;
fn load_partial_mat3(self, cols: [&[f32]; 9], fill: f32) -> Mat3Wide<S>;
fn splat_mat<const R: usize, const C: usize>(self, m: [[f32; C]; R]) -> MatWide<S, R, C>;
fn load_mat<const R: usize, const C: usize>(self, planes: [[&[f32]; C]; R]) -> MatWide<S, R, C>;
fn load_partial_mat<const R: usize, const C: usize>(
self,
planes: [[&[f32]; C]; R],
fill: f32,
) -> MatWide<S, R, C>;
}
impl<S: Backend<f32>> GangGlamExt<S> for Gang<S> {
#[inline(always)]
fn splat_vec3(self, v: Vec3) -> Vec3Wide<S> {
Vec3Wide(self.splat_n([v.x, v.y, v.z]))
}
#[inline(always)]
fn gather_vec3(self, s: &[Vec3], fill: f32) -> Vec3Wide<S> {
Vec3Wide(self.gather_n(s, [fill; 3], |v| [v.x, v.y, v.z]))
}
#[inline(always)]
fn gather_plane(self, s: &[(Vec3, f32)], fill: f32) -> (Vec3Wide<S>, Varying<f32, S>) {
let [nx, ny, nz, d] = self.gather_n(s, [fill; 4], |&(n, dd)| [n.x, n.y, n.z, dd]);
(Vec3Wide([nx, ny, nz]), d)
}
#[inline(always)]
fn load_vec3(self, cols: [&[f32]; 3]) -> Vec3Wide<S> {
Vec3Wide(self.load_n(cols))
}
#[inline(always)]
fn load_partial_vec3(self, cols: [&[f32]; 3], fill: f32) -> Vec3Wide<S> {
Vec3Wide(self.load_partial_n(cols, fill))
}
#[inline(always)]
fn splat_mat3(self, m: Mat3) -> Mat3Wide<S> {
Mat3Wide(self.splat_n(m.to_cols_array()))
}
#[inline(always)]
fn load_mat3(self, cols: [&[f32]; 9]) -> Mat3Wide<S> {
Mat3Wide(self.load_n(cols))
}
#[inline(always)]
fn load_partial_mat3(self, cols: [&[f32]; 9], fill: f32) -> Mat3Wide<S> {
Mat3Wide(self.load_partial_n(cols, fill))
}
#[inline(always)]
fn splat_mat<const R: usize, const C: usize>(self, m: [[f32; C]; R]) -> MatWide<S, R, C> {
MatWide(core::array::from_fn(|i| self.splat_n(m[i])))
}
#[inline(always)]
fn load_mat<const R: usize, const C: usize>(self, planes: [[&[f32]; C]; R]) -> MatWide<S, R, C> {
MatWide(planes.map(|row| self.load_n(row)))
}
#[inline(always)]
fn load_partial_mat<const R: usize, const C: usize>(
self,
planes: [[&[f32]; C]; R],
fill: f32,
) -> MatWide<S, R, C> {
MatWide(planes.map(|row| self.load_partial_n(row, fill)))
}
}