#if USE_SIMD
import simd
#endif


#if USE_SIMD
public typealias Matrix3x3 = simd_float3x3
public extension Matrix3x3
{
	typealias T = Float
}
#else
public struct Matrix3x3<T: FloatingPoint>: Equatable
{
	public var m00: T, m01: T, m02: T
	public var m10: T, m11: T, m12: T
	public var m20: T, m21: T, m22: T

	public init()
	{
		self.m00 = 1; self.m01 = 0; self.m02 = 0
		self.m10 = 0; self.m11 = 1; self.m12 = 0
		self.m20 = 0; self.m21 = 0; self.m22 = 1
	}

	public init(
		_ a00: T, _ a01: T, _ a02: T,
		_ a10: T, _ a11: T, _ a12: T,
		_ a20: T, _ a21: T, _ a22: T)
	{
		self.m00 = a00; self.m01 = a01; self.m02 = a02
		self.m10 = a10; self.m11 = a11; self.m12 = a12
		self.m20 = a20; self.m21 = a21; self.m22 = a22
	}
}

public extension Matrix3x3
{
	init(_ row0: Vector3<T>, _ row1: Vector3<T>, _ row2: Vector3<T>)
	{
		self.m00 = row0.x; self.m01 = row0.y; self.m02 = row0.z
		self.m10 = row1.x; self.m11 = row1.y; self.m12 = row1.z
		self.m20 = row2.x; self.m21 = row2.y; self.m22 = row2.z
	}

	@inline(__always) var identity: Self
	{
		Self(
			1, 0, 0,
			0, 1, 0,
			0, 0, 1)
	}

	@inline(__always) var transpose: Self
	{
		Self(
			m00, m10, m20,
			m01, m11, m21,
			m02, m12, m22)
	}

	static func * (lhs: Self, rhs: Self) -> Self
	{
		Self(
			lhs.m00 * rhs.m00 + lhs.m01 * rhs.m10 + lhs.m02 * rhs.m20,
			lhs.m00 * rhs.m01 + lhs.m01 * rhs.m11 + lhs.m02 * rhs.m21,
			lhs.m00 * rhs.m02 + lhs.m01 * rhs.m12 + lhs.m02 * rhs.m22,
			lhs.m10 * rhs.m00 + lhs.m11 * rhs.m10 + lhs.m12 * rhs.m20,
			lhs.m10 * rhs.m01 + lhs.m11 * rhs.m11 + lhs.m12 * rhs.m21,
			lhs.m10 * rhs.m02 + lhs.m11 * rhs.m12 + lhs.m12 * rhs.m22,
			lhs.m20 * rhs.m00 + lhs.m21 * rhs.m10 + lhs.m22 * rhs.m20,
			lhs.m20 * rhs.m01 + lhs.m21 * rhs.m11 + lhs.m22 * rhs.m21,
			lhs.m20 * rhs.m02 + lhs.m21 * rhs.m12 + lhs.m22 * rhs.m22)
	}
}
#endif

public extension Matrix3x3
{
	@inline(__always) static func lookAt(from: Vector3<T> = .zero, to: Vector3<T>, up: Vector3<T> = .up) -> Self
	{
		let direction = (to - from).normalised
		let normal    = -direction
		let bitangent = up.cross(normal).normalised
		let tangent   = normal.cross(bitangent).normalised

		return Self(
			.init(bitangent.x, tangent.x, normal.x),
			.init(bitangent.y, tangent.y, normal.y),
			.init(bitangent.z, tangent.z, normal.z))
	}
}

#if USE_SIMD
public typealias Mat3f = Matrix3x3
#else
public typealias Mat3f = Matrix3x3<Float>
public typealias Mat3d = Matrix3x3<Double>
#endif
