package sectr

/*
Vec3    : 3D Vector    (x, y, z)              (3x1) 4D Expression : (x, y, z, 0)
Bivec3  : 3D Bivector  (yz, zx, xy)           (3x1)
Trivec3 : 3D Trivector (xyz)                  (1x1)
Rotor3  : 3D Rotation Versor-Transform        (4x1)
Motor3  : 3D Rotation & Translation Transform (4x2)
*/

Vec3     :: [3]f32
Vec4     :: [4]f32

Bivec3 :: struct #raw_union {
	using _   : struct { yz, zx, xy : f32 },
	using xyz : Vec3,
}

Trivec3 :: distinct f32

Rotor3 :: struct {
	using bv : Bivec3,
	      s  : f32,     // Scalar
}

Shifter3 :: struct {
	using bv : Bivec3,
	      s  : f32,    // Scalar
}

Motor3 :: struct {
	rotor : Rotor3,
	md    : Shifter3,
}

UnitVec3   :: distinct Vec3
UnitVec4   :: distinct Vec4
UnitBivec3 :: distinct Bivec3

//region Vec3

vec3_via_f32s :: #force_inline proc "contextless" (x, y, z : f32) -> Vec3 { return {x, y, z} }

// complement_vec3 :: #force_inline proc "contextless" ( v : Vec3 ) -> Bivec3 {return transmute(Bivec3) v}

cross_vec3 :: proc "contextless" (a, b : Vec3) -> (v : Vec3) {
	v = vec3( wedge(a, b))
	return
}

dot_vec3 :: proc "contextless" ( a, b : Vec3 ) -> (s : f32) {
	mult := a * b // array multiply
	s     = mult.x + mult.y + mult.z
	return
}

inverse_mag_vec3 :: proc "contextless" (v : Vec3) -> (result : f32) {
	square := pow2(v)
	result  = inverse_sqrt( square )
	return
}

magnitude_vec3 :: proc "contextless" (v : Vec3) -> (mag : f32) {
	square := pow2(v)
	mag     = sqrt(square)
	return
}

normalize_vec3 :: proc "contextless" (v : Vec3) -> (unit_v : UnitVec3) {
	unit_v = transmute(UnitVec3) (v * inverse_mag(v))
	return
}

pow2_vec3 :: #force_inline proc "contextless" ( v : Vec3 ) -> (s : f32) {	return dot(v, v) }

project_vec3 :: proc "contextless" ( a, b : Vec3 ) -> ( a_to_b : Vec3 ) {
	return
}

reject_vec3 :: proc "contextless" ( a, b : Vec3 ) -> ( a_from_b : Vec3 ) {
	return
}

project_v3_unitv3 :: proc "contextless" ( v : Vec3, u : UnitVec3 ) -> (v_to_u : Vec3) {
	inner := dot(v, u)
	v_to_u = (transmute(Vec3) u) * inner
	return
}
project_unitv3_v3 :: #force_inline proc "contextless" (u : UnitVec3, v : Vec3) -> (u_to_v : Vec3) {
	inner := dot(u, v)
	u_to_v = v * inner
	return
}

// Anti-wedge of vectors
regress_vec3 :: proc "contextless" ( a, b : Vec3 ) -> f32 {
	return a.x * b.y - a.y * b.x
}

reject_v3_unitv3 :: proc "contextless" ( v : Vec3, u : UnitVec3 ) -> ( v_from_u : Vec3) {
	inner   := dot(v, u)
	v_from_u = (v - (transmute(Vec3) u)) * inner
	return
}
reject_unitv3_v3 :: proc "contextless" ( v : Vec3, u : UnitVec3 ) -> ( u_from_v : Vec3) {
	inner   := dot(u, v)
	u_from_v = ((transmute(Vec3) u) - v) * inner
	return
}

// Combines the deimensions that are present in a & b
wedge_vec3 :: proc "contextless" (a, b : Vec3) -> (bv : Bivec3) {
	yzx_zxy := a.yzx * b.zxy
	zxy_yzx := a.zxy * b.yzx
	bv       = transmute(Bivec3) (yzx_zxy - zxy_yzx)
	return
}

//endregion Vec3

//region Bivec3
bivec3_via_f32s :: #force_inline proc "contextless" (yz, zx, xy : f32) -> Bivec3 {return { xyz = {yz, zx, xy} }}

complement_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> Bivec3 {return transmute(Bivec3) b.xyz}

//region Operations isomoprhic to vectors
negate_bivec3      :: #force_inline proc "contextless" (b : Bivec3)             -> Bivec3     {return transmute(Bivec3) -b.xyz}
add_bivec3         :: #force_inline proc "contextless" (a,          b : Bivec3) -> Bivec3     {return transmute(Bivec3) (a.xyz + b.xyz)}
sub_bivec3         :: #force_inline proc "contextless" (a,          b : Bivec3) -> Bivec3     {return transmute(Bivec3) (a.xyz - b.xyz)}
mul_bivec3         :: #force_inline proc "contextless" (a,          b : Bivec3) -> Bivec3     {return transmute(Bivec3) (a.xyz * b.xyz)}
mul_bivec3_f32     :: #force_inline proc "contextless" (b : Bivec3, s : f32)    -> Bivec3     {return transmute(Bivec3) (b.xyz * s)}
mul_f32_bivec3     :: #force_inline proc "contextless" (s : f32,    b : Bivec3) -> Bivec3     {return transmute(Bivec3) (s * b.xyz)}
div_bivec3_f32     :: #force_inline proc "contextless" (b : Bivec3, s : f32)    -> Bivec3     {return transmute(Bivec3) (b.xyz / s)}
inverse_mag_bivec3 :: #force_inline proc "contextless" (b : Bivec3)             -> f32        {return inverse_mag_vec3(b.xyz)}
magnitude_bivec3   :: #force_inline proc "contextless" (b : Bivec3)             -> f32        {return magnitude_vec3  (b.xyz)}
normalize_bivec3   :: #force_inline proc "contextless" (b : Bivec3)             -> UnitBivec3 {return transmute(UnitBivec3) normalize_vec3(b.xyz)}
squared_mag_bivec3 :: #force_inline proc "contextless" (b : Bivec3)             -> f32        {return pow2_vec3(b.xyz)}
//endregion Operations isomoprhic to vectors

// The wedge of a bi-vector in 3D vector space results in a Trivector represented as a scalar.
// This scalar usually resolves to zero with six possible exceptions that lead to the negative volume element.
wedge_bivec3 :: proc ( a, b : Bivec3 ) -> f32 {
	s := a.yz + b.yz + a.zx + b.zx + a.xy + b.xy
	return s
}

// anti-wedge (Combines dimensions that are absent from a & b)
regress_bivec3    :: #force_inline proc "contextless" ( a, b : Bivec3 )      -> Vec3 {return wedge_vec3(vec3(a), vec3(b))}
regress_bivec3_v  :: #force_inline proc "contextless" (b : Bivec3, v : Vec3) -> f32  {return regress_vec3(b.xyz, v)}
regress_v3_bivec3 :: #force_inline proc "contextless" (v : Vec3, b : Bivec3) -> f32  {return regress_vec3(b.xyz, v)}

//endregion Bivec3

//region Rotor3

rotor3_via_comps :: proc "contextless" (yz, zx, xy, scalar : f32) -> (rotor : Rotor3) {
	rotor = Rotor3 {bivec3_via_f32s(yz, zx, xy), scalar}
	return
}

rotor3_via_bv_s :: proc "contextless" (bv : Bivec3, scalar : f32) -> (rotor : Rotor3) {
	rotor = Rotor3 {bv, scalar}
	return
}

rotor3_via_from_to :: proc "contextless" ( from, to : Vec3 ) -> (rotor : Rotor3) {
	scalar := 1 + dot( from, to )
	return
}

inverse_mag_rotor3 :: proc "contextless" (rotor : Rotor3) -> (s : f32) {
	return
}

magnitude_rotor3 :: proc "contextless" (rotor : Rotor3) -> (s : f32) {
	return
}

squared_mag :: proc "contextless" (rotor : Rotor3) -> (s : f32) {
	return
}

reverse_rotor3 :: proc "contextless" (rotor : Rotor3) -> (reversed : Rotor3) {
	reversed = { negate_bivec3(rotor.bv), rotor.s }
	return
}

//endregion Rotor3

//region Flat Projective Geometry

Point3     :: distinct Vec3
PointFlat3 :: distinct Vec4
Line3  :: struct {
	weight : Vec3,
	bulk   : Bivec3,
}
Plane3 :: distinct Vec4 // 4D Anti-vector

// aka: wedge operation for points
join_point3 :: proc "contextless" (p, q : Point3) -> (l : Line3) {
	weight := sub(q, p)
	bulk   := wedge(vec3(p), vec3(q))
	l       = {weight, bulk}
	return
}

join_pointflat3 :: proc "contextless" (p, q : PointFlat3) -> (l : Line3) {
	weight := vec3(
		p.w * q.x - p.x * q.w,
		p.w * q.y - p.y * q.w,
		p.w * q.z - p.z * q.w
	)
	bulk   := wedge(vec3(p), vec3(q))
	l       = { weight, bulk}
	return
}

sub_point3 :: proc "contextless" (a, b : Point3) -> (v : Vec3) {
	v = vec3(a) - vec3(b)
	return
}

//endregion Flat Projective Geometry

//region Rational Trig

quadrance :: proc "contextless" (a, b : Point3) -> (q : f32) {
	q = pow2( sub(a, b))
	return
}

// Assumes the weight component is normalized.
spread :: proc "contextless" (l, m : Line3) -> (s : f32) {
	s = dot(l.weight, m.weight)
	return
}

//endregion Rational Trig