Newer
Older
kotlin-webgl-test / src / main / kotlin / games / perses / math / Matrix4.kt
package games.perses.math

import org.khronos.webgl.Float32Array
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.tan

/**
 * User: rnentjes
 * Date: 17-4-16
 * Time: 15:43
 */
class Matrix4 {

  internal var matrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)

  internal var temp = FloatArray(16)

  private val translateMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)

  private val scaleMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)

  private val rotateXMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)

  private val rotateYMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)

  private val rotateZMatrix = floatArrayOf(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)

  fun get(): FloatArray {
    return matrix
  }

  fun getFloat32Array() = Float32Array(get().toTypedArray())

  fun set(values: FloatArray) {
    if (values.size != 16) {
      throw IllegalArgumentException("Matrix size should be 16!")
    }

    matrix = values
  }

  fun setPerspectiveProjection(angle: Float, imageAspectRatio: Float, near: Float, far: Float) {
    val r = (angle / 180f * PI).toFloat()
    val f = (1.0f / tan((r / 2.0f).toDouble())).toFloat()

    matrix[0] = f / imageAspectRatio
    matrix[1] = 0.0f
    matrix[2] = 0.0f
    matrix[3] = 0.0f

    matrix[4] = 0.0f
    matrix[5] = f
    matrix[6] = 0.0f
    matrix[7] = 0.0f

    matrix[8] = 0.0f
    matrix[9] = 0.0f
    matrix[10] = -(far + near) / (far - near)
    matrix[11] = -1.0f

    matrix[12] = 0.0f
    matrix[13] = 0.0f
    matrix[14] = -(2.0f * far * near) / (far - near)
    matrix[15] = 0.0f
  }

  fun setOrthographicProjection(left: Float, right: Float, bottom: Float, top: Float, near: Float, far: Float) {
    matrix[0] = 2f / (right - left)
    matrix[1] = 0f
    matrix[2] = 0f
    matrix[3] = 0f

    matrix[4] = 0f
    matrix[5] = 2f / (top - bottom)
    matrix[6] = 0f
    matrix[7] = 0f

    matrix[8] = 0f
    matrix[9] = 0f
    matrix[10] = -2f / (far - near)
    matrix[11] = 0f

    matrix[12] = -(right + left) / (right - left)
    matrix[13] = -(top + bottom) / (top - bottom)
    matrix[14] = -(far + near) / (far - near)
    matrix[15] = 1f
  }

  fun setToIdentity() {
    matrix[0] = 1.0f
    matrix[1] = 0.0f
    matrix[2] = 0.0f
    matrix[3] = 0.0f
    matrix[4] = 0.0f
    matrix[5] = 1.0f
    matrix[6] = 0.0f
    matrix[7] = 0.0f
    matrix[8] = 0.0f
    matrix[9] = 0.0f
    matrix[10] = 1.0f
    matrix[11] = 0.0f
    matrix[12] = 0.0f
    matrix[13] = 0.0f
    matrix[14] = 0.0f
    matrix[15] = 1.0f
  }

  fun mul(other: Matrix4) {
    mul(other.get())
  }

  protected fun mul(other: FloatArray) {
    if (other.size != 16) {
      throw IllegalArgumentException("Matrix size should be 16!")
    }

    temp[0] = matrix[0] * other[0] + matrix[1] * other[4] + matrix[2] * other[8] + matrix[3] * other[12]
    temp[1] = matrix[0] * other[1] + matrix[1] * other[5] + matrix[2] * other[9] + matrix[3] * other[13]
    temp[2] = matrix[0] * other[2] + matrix[1] * other[6] + matrix[2] * other[10] + matrix[3] * other[14]
    temp[3] = matrix[0] * other[3] + matrix[1] * other[7] + matrix[2] * other[11] + matrix[3] * other[15]
    temp[4] = matrix[4] * other[0] + matrix[5] * other[4] + matrix[6] * other[8] + matrix[7] * other[12]
    temp[5] = matrix[4] * other[1] + matrix[5] * other[5] + matrix[6] * other[9] + matrix[7] * other[13]
    temp[6] = matrix[4] * other[2] + matrix[5] * other[6] + matrix[6] * other[10] + matrix[7] * other[14]
    temp[7] = matrix[4] * other[3] + matrix[5] * other[7] + matrix[6] * other[11] + matrix[7] * other[15]
    temp[8] = matrix[8] * other[0] + matrix[9] * other[4] + matrix[10] * other[8] + matrix[11] * other[12]
    temp[9] = matrix[8] * other[1] + matrix[9] * other[5] + matrix[10] * other[9] + matrix[11] * other[13]
    temp[10] = matrix[8] * other[2] + matrix[9] * other[6] + matrix[10] * other[10] + matrix[11] * other[14]
    temp[11] = matrix[8] * other[3] + matrix[9] * other[7] + matrix[10] * other[11] + matrix[11] * other[15]
    temp[12] = matrix[12] * other[0] + matrix[13] * other[4] + matrix[14] * other[8] + matrix[15] * other[12]
    temp[13] = matrix[12] * other[1] + matrix[13] * other[5] + matrix[14] * other[9] + matrix[15] * other[13]
    temp[14] = matrix[12] * other[2] + matrix[13] * other[6] + matrix[14] * other[10] + matrix[15] * other[14]
    temp[15] = matrix[12] * other[3] + matrix[13] * other[7] + matrix[14] * other[11] + matrix[15] * other[15]

    matrix[0] = temp[0]
    matrix[1] = temp[1]
    matrix[2] = temp[2]
    matrix[3] = temp[3]
    matrix[4] = temp[4]
    matrix[5] = temp[5]
    matrix[6] = temp[6]
    matrix[7] = temp[7]
    matrix[8] = temp[8]
    matrix[9] = temp[9]
    matrix[10] = temp[10]
    matrix[11] = temp[11]
    matrix[12] = temp[12]
    matrix[13] = temp[13]
    matrix[14] = temp[14]
    matrix[15] = temp[15]
  }

  fun translate(x: Float, y: Float, z: Float) {
    translateMatrix[12] = x
    translateMatrix[13] = y
    translateMatrix[14] = z

    mul(translateMatrix)
  }

  fun scale(x: Float, y: Float, z: Float) {
    scaleMatrix[0] = x
    scaleMatrix[5] = y
    scaleMatrix[10] = z

    mul(scaleMatrix)
  }

  fun rotateX(angle: Float) {
    rotateXMatrix[5] = cos(angle.toDouble()).toFloat()
    rotateXMatrix[6] = (-sin(angle.toDouble())).toFloat()
    rotateXMatrix[9] = sin(angle.toDouble()).toFloat()
    rotateXMatrix[10] = cos(angle.toDouble()).toFloat()

    mul(rotateXMatrix)
  }

  fun rotateY(angle: Float) {
    rotateYMatrix[0] = cos(angle.toDouble()).toFloat()
    rotateYMatrix[2] = sin(angle.toDouble()).toFloat()
    rotateYMatrix[8] = (-sin(angle.toDouble())).toFloat()
    rotateYMatrix[10] = cos(angle.toDouble()).toFloat()

    mul(rotateYMatrix)
  }

  fun rotateZ(angle: Float) {
    rotateZMatrix[0] = cos(angle.toDouble()).toFloat()
    rotateZMatrix[1] = sin(angle.toDouble()).toFloat()
    rotateZMatrix[4] = (-sin(angle.toDouble())).toFloat()
    rotateZMatrix[5] = cos(angle.toDouble()).toFloat()

    mul(rotateZMatrix)
  }
}