Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
commonMain.ru.casperix.math.quad_matrix.float32.Matrix4f.kt Maven / Gradle / Ivy
package ru.casperix.math.quad_matrix.float32
import ru.casperix.math.quad_matrix.QuadMatrix
import ru.casperix.math.quad_matrix.QuadMatrixBuilder
import ru.casperix.math.quad_matrix.float64.Matrix4d
import ru.casperix.math.quaternion.float32.QuaternionFloat
import ru.casperix.math.vector.float32.Vector3f
import ru.casperix.misc.clone
import kotlinx.serialization.Serializable
import kotlin.math.PI
import kotlin.math.tan
@Serializable
data class Matrix4f(val data: FloatArray) : QuadMatrix {
// constructor(vararg data: Float) : this(floatArrayOf(*data))
init {
if (data.size != 16) throw Error("Source expected 16 elements, but actual ${data.size}")
}
operator fun get(x: Int, y: Int): Float {
return data[x + y * 4]
}
operator fun get(index: Int): Float {
return data[index]
}
fun getTranslate(): Vector3f {
return Vector3f(data[12], data[13], data[14])
}
fun transform(value: Vector3f): Vector3f {
val m = data
val rx = value.x * m[0] + value.y * m[4] + value.z * m[8] + m[12]
val ry = value.x * m[1] + value.y * m[5] + value.z * m[9] + m[13]
val rz = value.x * m[2] + value.y * m[6] + value.z * m[10] + m[14]
val rw = 1 / (value.x * m[3] + value.y * m[7] + value.z * m[11] + m[15])
return Vector3f(rx * rw, ry * rw, rz * rw)
}
override operator fun times(other: Matrix4f): Matrix4f {
val A = data
val B = other.data
val target = floatArrayOf(
A[i00] * B[i00] + A[i10] * B[i01] + A[i20] * B[i02] + A[i30] * B[i03],
A[i00] * B[i10] + A[i10] * B[i11] + A[i20] * B[i12] + A[i30] * B[i13],
A[i00] * B[i20] + A[i10] * B[i21] + A[i20] * B[i22] + A[i30] * B[i23],
A[i00] * B[i30] + A[i10] * B[i31] + A[i20] * B[i32] + A[i30] * B[i33],
A[i01] * B[i00] + A[i11] * B[i01] + A[i21] * B[i02] + A[i31] * B[i03],
A[i01] * B[i10] + A[i11] * B[i11] + A[i21] * B[i12] + A[i31] * B[i13],
A[i01] * B[i20] + A[i11] * B[i21] + A[i21] * B[i22] + A[i31] * B[i23],
A[i01] * B[i30] + A[i11] * B[i31] + A[i21] * B[i32] + A[i31] * B[i33],
A[i02] * B[i00] + A[i12] * B[i01] + A[i22] * B[i02] + A[i32] * B[i03],
A[i02] * B[i10] + A[i12] * B[i11] + A[i22] * B[i12] + A[i32] * B[i13],
A[i02] * B[i20] + A[i12] * B[i21] + A[i22] * B[i22] + A[i32] * B[i23],
A[i02] * B[i30] + A[i12] * B[i31] + A[i22] * B[i32] + A[i32] * B[i33],
A[i03] * B[i00] + A[i13] * B[i01] + A[i23] * B[i02] + A[i33] * B[i03],
A[i03] * B[i10] + A[i13] * B[i11] + A[i23] * B[i12] + A[i33] * B[i13],
A[i03] * B[i20] + A[i13] * B[i21] + A[i23] * B[i22] + A[i33] * B[i23],
A[i03] * B[i30] + A[i13] * B[i31] + A[i23] * B[i32] + A[i33] * B[i33],
)
return Matrix4f(target)
}
fun toMatrix4d(): Matrix4d {
return Matrix4d(DoubleArray(16) { this[it].toDouble() })
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Matrix4f
if (!data.contentEquals(other.data)) return false
return true
}
override fun hashCode(): Int {
return data.hashCode()
}
override fun transpose(): Matrix4f {
return Matrix4f(
floatArrayOf(
data[i00], data[i01], data[i02], data[i03],
data[i10], data[i11], data[i12], data[i13],
data[i20], data[i21], data[i22], data[i23],
data[i30], data[i31], data[i32], data[i33],
)
)
}
override fun determinant(): Float {
return data[i30] * data[i21] * data[i12] * data[i03] - data[i20] * data[i31] * data[i12] * data[i03] - data[i30] * data[i11] * data[i22] * data[i03] + data[i10] * data[i31] * data[i22] * data[i03] + data[i20] * data[i11] * data[i32] * data[i03] - data[i10] * data[i21] * data[i32] * data[i03] - data[i30] * data[i21] * data[i02] * data[i13] + data[i20] * data[i31] * data[i02] * data[i13] + data[i30] * data[i01] * data[i22] * data[i13] - data[i00] * data[i31] * data[i22] * data[i13] - data[i20] * data[i01] * data[i32] * data[i13] + data[i00] * data[i21] * data[i32] * data[i13] + data[i30] * data[i11] * data[i02] * data[i23] - data[i10] * data[i31] * data[i02] * data[i23] - data[i30] * data[i01] * data[i12] * data[i23] + data[i00] * data[i31] * data[i12] * data[i23] + data[i10] * data[i01] * data[i32] * data[i23] - data[i00] * data[i11] * data[i32] * data[i23] - data[i20] * data[i11] * data[i02] * data[i33] + data[i10] * data[i21] * data[i02] * data[i33] + data[i20] * data[i01] * data[i12] * data[i33] - data[i00] * data[i21] * data[i12] * data[i33] - data[i10] * data[i01] * data[i22] * data[i33] + data[i00] * data[i11] * data[i22] * data[i33]
}
fun setTranslate(value: Vector3f): Matrix4f {
val output = data.clone()
output.set(12, value.x)
output.set(13, value.y)
output.set(14, value.z)
return Matrix4f(output)
}
fun toMatrix3f(): Matrix3f {
return Matrix3f(
floatArrayOf(
data[0], data[1], data[2],
data[4], data[5], data[6],
data[8], data[9], data[10],
)
)
}
override fun inverse(): Matrix4f {
val l_det = data[3] * data[6] * data[9] * data[12] -
data[2] * data[7] * data[9] * data[12] -
data[3] * data[5] * data[10] * data[12] +
data[1] * data[7] * data[10] * data[12] +
data[2] * data[5] * data[11] * data[12] -
data[1] * data[6] * data[11] * data[12] -
data[3] * data[6] * data[8] * data[13] +
data[2] * data[7] * data[8] * data[13] +
data[3] * data[4] * data[10] * data[13] -
data[0] * data[7] * data[10] * data[13] -
data[2] * data[4] * data[11] * data[13] +
data[0] * data[6] * data[11] * data[13] +
data[3] * data[5] * data[8] * data[14] -
data[1] * data[7] * data[8] * data[14] -
data[3] * data[4] * data[9] * data[14] +
data[0] * data[7] * data[9] * data[14] +
data[1] * data[4] * data[11] * data[14] -
data[0] * data[5] * data[11] * data[14] -
data[2] * data[5] * data[8] * data[15] +
data[1] * data[6] * data[8] * data[15] +
data[2] * data[4] * data[9] * data[15] -
data[0] * data[6] * data[9] * data[15] -
data[1] * data[4] * data[10] * data[15] +
data[0] * data[5] * data[10] * data[15]
if (l_det == 0f) throw RuntimeException("non-indataertible matrix");
val m0 =
data[9] * data[14] * data[7] - data[13] * data[10] * data[7] + data[13] * data[6] * data[11] - data[5] * data[14] * data[11] - data[9] * data[6] * data[15] + data[5] * data[10] * data[15]
val m4 =
data[12] * data[10] * data[7] - data[8] * data[14] * data[7] - data[12] * data[6] * data[11] + data[4] * data[14] * data[11] + data[8] * data[6] * data[15] - data[4] * data[10] * data[15]
val m8 =
data[8] * data[13] * data[7] - data[12] * data[9] * data[7] + data[12] * data[5] * data[11] - data[4] * data[13] * data[11] - data[8] * data[5] * data[15] + data[4] * data[9] * data[15]
val m12 =
data[12] * data[9] * data[6] - data[8] * data[13] * data[6] - data[12] * data[5] * data[10] + data[4] * data[13] * data[10] + data[8] * data[5] * data[14] - data[4] * data[9] * data[14]
val m1 =
data[13] * data[10] * data[3] - data[9] * data[14] * data[3] - data[13] * data[2] * data[11] + data[1] * data[14] * data[11] + data[9] * data[2] * data[15] - data[1] * data[10] * data[15]
val m5 =
data[8] * data[14] * data[3] - data[12] * data[10] * data[3] + data[12] * data[2] * data[11] - data[0] * data[14] * data[11] - data[8] * data[2] * data[15] + data[0] * data[10] * data[15]
val m9 =
data[12] * data[9] * data[3] - data[8] * data[13] * data[3] - data[12] * data[1] * data[11] + data[0] * data[13] * data[11] + data[8] * data[1] * data[15] - data[0] * data[9] * data[15]
val m13 =
data[8] * data[13] * data[2] - data[12] * data[9] * data[2] + data[12] * data[1] * data[10] - data[0] * data[13] * data[10] - data[8] * data[1] * data[14] + data[0] * data[9] * data[14]
val m2 =
data[5] * data[14] * data[3] - data[13] * data[6] * data[3] + data[13] * data[2] * data[7] - data[1] * data[14] * data[7] - data[5] * data[2] * data[15] + data[1] * data[6] * data[15]
val m6 =
data[12] * data[6] * data[3] - data[4] * data[14] * data[3] - data[12] * data[2] * data[7] + data[0] * data[14] * data[7] + data[4] * data[2] * data[15] - data[0] * data[6] * data[15]
val m10 =
data[4] * data[13] * data[3] - data[12] * data[5] * data[3] + data[12] * data[1] * data[7] - data[0] * data[13] * data[7] - data[4] * data[1] * data[15] + data[0] * data[5] * data[15]
val m14 =
data[12] * data[5] * data[2] - data[4] * data[13] * data[2] - data[12] * data[1] * data[6] + data[0] * data[13] * data[6] + data[4] * data[1] * data[14] - data[0] * data[5] * data[14]
val m3 =
data[9] * data[6] * data[3] - data[5] * data[10] * data[3] - data[9] * data[2] * data[7] + data[1] * data[10] * data[7] + data[5] * data[2] * data[11] - data[1] * data[6] * data[11]
val m7 =
data[4] * data[10] * data[3] - data[8] * data[6] * data[3] + data[8] * data[2] * data[7] - data[0] * data[10] * data[7] - data[4] * data[2] * data[11] + data[0] * data[6] * data[11]
val m11 =
data[8] * data[5] * data[3] - data[4] * data[9] * data[3] - data[8] * data[1] * data[7] + data[0] * data[9] * data[7] + data[4] * data[1] * data[11] - data[0] * data[5] * data[11]
val m15 =
data[4] * data[9] * data[2] - data[8] * data[5] * data[2] + data[8] * data[1] * data[6] - data[0] * data[9] * data[6] - data[4] * data[1] * data[10] + data[0] * data[5] * data[10]
val inv_det = 1.0f / l_det;
return Matrix4f(
floatArrayOf(
m0 * inv_det,
m1 * inv_det,
m2 * inv_det,
m3 * inv_det,
m4 * inv_det,
m5 * inv_det,
m6 * inv_det,
m7 * inv_det,
m8 * inv_det,
m9 * inv_det,
m10 * inv_det,
m11 * inv_det,
m12 * inv_det,
m13 * inv_det,
m14 * inv_det,
m15 * inv_det,
)
)
}
companion object : QuadMatrixBuilder {
private val i00 = 0
private val i10 = 1
private val i20 = 2
private val i30 = 3
private val i01 = 4
private val i11 = 5
private val i21 = 6
private val i31 = 7
private val i02 = 8
private val i12 = 9
private val i22 = 10
private val i32 = 11
private val i03 = 12
private val i13 = 13
private val i23 = 14
private val i33 = 15
fun byIndex(factory: (Int) -> Float): Matrix4f {
return Matrix4f(FloatArray(16) { factory(it) })
}
fun fromValues(vararg values: Float): Matrix4f {
return byIndex { values.getOrNull(it) ?: 0f }
}
val IDENTITY = byIndex { if (it % 5 == 0) 1f else 0f }
override fun translate(value: Vector3f): Matrix4f {
return fromValues(
1f, 0f, 0f, 0f,
0f, 1f, 0f, 0f,
0f, 0f, 1f, 0f,
value.x, value.y, value.z, 1f
)
}
override fun scale(value: Vector3f): Matrix4f {
return fromValues(
value.x, 0f, 0f, 0f,
0f, value.y, 0f, 0f,
0f, 0f, value.z, 0f,
0f, 0f, 0f, 1f
)
}
override fun rotate(value: QuaternionFloat): Matrix4f {
val xx = value.x * value.x
val yy = value.y * value.y
val zz = value.z * value.z
val xy = value.x * value.y
val zw = value.z * value.w
val zx = value.z * value.x
val yw = value.y * value.w
val yz = value.y * value.z
val xw = value.x * value.w
return Matrix4f(
floatArrayOf(
/*0*/ (1f - (2f * (yy + zz))),
/*1*/ 2f * (xy + zw),
/*2*/ 2f * (zx - yw),
/*3*/ 0f,
/*4*/ 2f * (xy - zw),
/*5*/ (1f - (2f * (zz + xx))),
/*6*/ 2f * (yz + xw),
/*7*/ 0f,
/*8*/ 2f * (zx + yw),
/*9*/ 2f * (yz - xw),
/*10*/ (1f - (2f * (yy + xx))),
/*11*/ 0f,
/*12*/ 0f,
/*13*/ 0f,
/*14*/ 0f,
/*15*/ 1f
)
)
}
fun compose(translate: Vector3f, scale: Vector3f, rotation: QuaternionFloat): Matrix4f {
val xx = rotation.x * rotation.x
val yy = rotation.y * rotation.y
val zz = rotation.z * rotation.z
val xy = rotation.x * rotation.y
val zw = rotation.z * rotation.w
val zx = rotation.z * rotation.x
val yw = rotation.y * rotation.w
val yz = rotation.y * rotation.z
val xw = rotation.x * rotation.w
return Matrix4f(
floatArrayOf(
/*0*/ (1f - (2f * (yy + zz))) * scale.x,
/*1*/ 2f * (xy + zw) * scale.x,
/*2*/ 2f * (zx - yw) * scale.x,
/*3*/ 0f,
/*4*/ 2f * (xy - zw) * scale.y,
/*5*/ (1f - (2f * (zz + xx))) * scale.y,
/*6*/ 2f * (yz + xw) * scale.y,
/*7*/ 0f,
/*8*/ 2f * (zx + yw) * scale.z,
/*9*/ 2f * (yz - xw) * scale.z,
/*10*/ (1f - (2f * (yy + xx))) * scale.z,
/*11*/ 0f,
/*12*/ translate.x,
/*13*/ translate.y,
/*14*/ translate.z,
/*15*/ 1f
)
)
}
fun orthographic(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float): Matrix4f {
val tx = -(right + left) / (right - left)
val ty = -(top + bottom) / (top - bottom)
val tz = -(far + near) / (far - near)
return Matrix4f(
floatArrayOf(
2f / (right - left), 0f, 0f, 0f,
0f, 2f / (top - bottom), 0f, 0f,
0f, 0f, -2f / (far - near), 0f,
tx, ty, tz, 1f,
)
)
}
fun frustum(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float): Matrix4f {
val a = (right + left) / (right - left)
val b = (top + bottom) / (top - bottom)
val c = -(far + near) / (far - near)
val d = -(2f * far * near) / (far - near)
return Matrix4f(
floatArrayOf(
2f * near / (right - left), 0f, 0f, 0f,
0f, 2f * near / (top - bottom), 0f, 0f,
a, b, c, -1f,
0f, 0f, d, 0f,
)
)
}
/**
* Creates a perspective projection matrix. Similar to
* `gluPerspective(fovy, aspec, zNear, zFar)`.
*
* @param fovy Field of view angle in degrees
* @param aspect The aspect ratio is the ratio of width to height
* @param near Distance from the viewer to the near clipping plane, must
* be positive
* @param far Distance from the viewer to the far clipping plane, must be
* positive
*
* @return Perspective matrix
*/
fun perspective(fovy: Float, aspect: Float, near: Float, far: Float): Matrix4f {
val f = (1f / tan(fovy.toDouble() * PI / 180f / 2f)).toFloat()
return Matrix4f(
floatArrayOf(
f / aspect, 0f, 0f, 0f,
0f, f, 0f, 0f,
0f, 0f, (far + near) / (near - far), -1f,
0f, 0f, 2f * far * near / (near - far), 0f,
)
)
}
fun createByAxis(xAxis: Vector3f, yAxis: Vector3f, zAxis: Vector3f): Matrix4f {
return fromValues(
xAxis.x, yAxis.x, zAxis.x, 0f,
xAxis.y, yAxis.y, zAxis.y, 0f,
xAxis.z, yAxis.z, zAxis.z, 0f,
0f, 0f, 0f, 1f
)
}
fun fromQuaternion(quaternion: QuaternionFloat): Matrix4f {
val xx = quaternion.x * quaternion.x
val yy = quaternion.y * quaternion.y
val zz = quaternion.z * quaternion.z
val xy = quaternion.x * quaternion.y
val zw = quaternion.z * quaternion.w
val zx = quaternion.z * quaternion.x
val yw = quaternion.y * quaternion.w
val yz = quaternion.y * quaternion.z
val xw = quaternion.x * quaternion.w
return fromValues(
/*0*/ 1f - (2f * (yy + zz)),
/*1*/ 2f * (xy + zw),
/*2*/ 2f * (zx - yw),
/*3*/ 0f,
/*4*/ 2f * (xy - zw),
/*5*/ 1f - (2f * (zz + xx)),
/*6*/ 2f * (yz + xw),
/*7*/ 0f,
/*8*/ 2f * (zx + yw),
/*9*/ 2f * (yz - xw),
/*10*/ 1f - (2f * (yy + xx)),
/*11*/ 0f,
/*12*/ 0f,
/*13*/ 0f,
/*14*/ 0f,
/*15*/ 1f
)
}
}
}