Skip to content

Instantly share code, notes, and snippets.

@elect86
Created December 15, 2021 14:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save elect86/4960063397eeeed0c609573e08145fe7 to your computer and use it in GitHub Desktop.
Save elect86/4960063397eeeed0c609573e08145fe7 to your computer and use it in GitHub Desktop.
@file:OptIn(kotlin.contracts.ExperimentalContracts::class)
package glm.vec2
import glm.*
import glm.extensions.*
import kotlin.jvm.*
import kotlin.math.abs
import kotlin.math.sqrt
import glm.vec1.*
import glm.vec2.*
import glm.vec3.*
import glm.vec4.*
import glm.mat2.*
import glm.mat2x3.*
import glm.mat2x4.*
import glm.mat3x2.*
import glm.mat3.*
import glm.mat3x4.*
import glm.mat4x2.*
import glm.mat4x3.*
import glm.mat4.*
open class Vec2(var array: FloatArray, var ofs: Int = 0) : Vec2T<Float>() {
override var x: Float
get() = array[ofs]
set(value) {
array[ofs] = value
}
override var y: Float
get() = array[ofs + 1]
set(value) {
array[ofs + 1] = value
}
// Implicit basic constructors
constructor() : this(FloatArray(2))
constructor(v: Vec2) : this(v.x, v.y)
// Explicit basic constructors
constructor(x: Float) : this(x, x)
constructor(x: Number) : this(x.f)
constructor(x: Float, y: Float) : this(floatArrayOf(x, y))
// Conversion scalar constructors
constructor(v: Vec1T<out Number>) : this(v.x.f)
// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
constructor(x: Number, y: Number) : this(x.f, y.f)
constructor(x: Number, y: Vec1T<out Number>) : this(x, y.x)
constructor(x: Vec1T<out Number>, y: Number) : this(x.x, y)
constructor(x: Vec1T<out Number>, y: Vec1T<out Number>) : this(x.x, y.x)
// Conversion vector constructors
// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
constructor(v: Vec2T<out Number>) : this(v.x, v.y)
constructor(v: Vec3T<out Number>) : this(v.x, v.y)
constructor(v: Vec4T<out Number>) : this(v.x, v.y)
// Unary arithmetic operators
operator fun plusAssign(scalar: Number) = plusAssign(scalar.f)
operator fun plusAssign(scalar: Float) {
x += scalar
y += scalar
}
operator fun plusAssign(v: Vec1T<out Number>) {
x += v.x.f
y += v.x.f
}
operator fun plusAssign(v: Vec1) {
x += v.x
y += v.x
}
operator fun plusAssign(v: Vec2T<out Number>) {
x += v.x.f
y += v.y.f
}
operator fun plusAssign(v: Vec2) {
x += v.x
y += v.y
}
operator fun minusAssign(scalar: Number) = minusAssign(scalar.f)
operator fun minusAssign(scalar: Float) {
x -= scalar
y -= scalar
}
operator fun minusAssign(v: Vec1T<out Number>) {
x -= v.x.f
y -= v.x.f
}
operator fun minusAssign(v: Vec1) {
x -= v.x
y -= v.x
}
operator fun minusAssign(v: Vec2T<out Number>) {
x -= v.x.f
y -= v.y.f
}
operator fun minusAssign(v: Vec2) {
x -= v.x
y -= v.y
}
operator fun timesAssign(scalar: Number) = timesAssign(scalar.f)
operator fun timesAssign(scalar: Float) {
x *= scalar
y *= scalar
}
operator fun timesAssign(v: Vec1T<out Number>) {
x *= v.x.f
y *= v.x.f
}
operator fun timesAssign(v: Vec1) {
x *= v.x
y *= v.x
}
operator fun timesAssign(v: Vec2T<out Number>) {
x *= v.x.f
y *= v.y.f
}
operator fun timesAssign(v: Vec2) {
x *= v.x
y *= v.y
}
operator fun divAssign(scalar: Number) = divAssign(scalar.f)
operator fun divAssign(scalar: Float) {
x /= scalar
y /= scalar
}
operator fun divAssign(v: Vec1T<out Number>) {
x /= v.x.f
y /= v.x.f
}
operator fun divAssign(v: Vec1) {
x /= v.x
y /= v.x
}
operator fun divAssign(v: Vec2T<out Number>) {
x /= v.x.f
y /= v.y.f
}
operator fun divAssign(v: Vec2) {
x /= v.x
y /= v.y
}
// Increment and decrement operators
operator fun inc(): Vec2 {
x++
y++
return this
}
operator fun dec(): Vec2 {
x--
y--
return this
}
operator fun invoke(x: Float, y: Float): Vec2 {
this.x = x
this.y = y
return this
}
// Unary bit operators TODO
// Unary operators
operator fun unaryPlus(): Vec2 = this
operator fun unaryMinus(): Vec2 = Vec2(-x, -y)
// Binary operators
operator fun plus(scalar: Float): Vec2 = plus(scalar, scalar, Vec2())
fun plus(scalar: Float, res: Vec2): Vec2 = plus(scalar, scalar, res)
inline fun plus(scalar: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
plus(x, y, scalar, scalar, res)
}
operator fun plus(v: Vec1): Vec2 = plus(v.x, v.x, Vec2())
fun plus(v: Vec1, res: Vec2): Vec2 = plus(v.x, v.x, res)
inline fun plus(v: Vec1, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
plus(x, y, v.x, v.x, res)
}
operator fun plus(v: Vec2): Vec2 = plus(v.x, v.y, Vec2())
fun plus(v: Vec2, res: Vec2): Vec2 = plus(v.x, v.y, res)
inline fun plus(v: Vec2, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
plus(x, y, v.x, v.y, res)
}
fun plus(x: Float, y: Float, res: Vec2): Vec2 = res(this.x + x, this.y + y)
inline fun plus(x: Float, y: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
plus(x, y, x, y, res)
}
operator fun minus(scalar: Float): Vec2 = minus(scalar, scalar, Vec2())
fun minus(scalar: Float, res: Vec2): Vec2 = minus(scalar, scalar, res)
inline fun minus(scalar: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
minus(x, y, scalar, scalar, res)
}
operator fun minus(v: Vec1): Vec2 = minus(v.x, v.x, Vec2())
fun minus(v: Vec1, res: Vec2): Vec2 = minus(v.x, v.x, res)
inline fun minus(v: Vec1, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
minus(x, y, v.x, v.x, res)
}
operator fun minus(v: Vec2): Vec2 = minus(v.x, v.y, Vec2())
fun minus(v: Vec2, res: Vec2): Vec2 = minus(v.x, v.y, res)
inline fun minus(v: Vec2, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
minus(x, y, v.x, v.y, res)
}
fun minus(x: Float, y: Float, res: Vec2): Vec2 = res(this.x - x, this.y - y)
inline fun minus(x: Float, y: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
minus(x, y, x, y, res)
}
operator fun times(scalar: Float): Vec2 = times(scalar, scalar, Vec2())
fun times(scalar: Float, res: Vec2): Vec2 = times(scalar, scalar, res)
inline fun times(scalar: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(x, y, scalar, scalar, res)
}
operator fun times(v: Vec1): Vec2 = times(v.x, v.x, Vec2())
fun times(v: Vec1, res: Vec2): Vec2 = times(v.x, v.x, res)
inline fun times(v: Vec1, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(x, y, v.x, v.x, res)
}
operator fun times(v: Vec2): Vec2 = times(v.x, v.y, Vec2())
fun times(v: Vec2, res: Vec2): Vec2 = times(v.x, v.y, res)
inline fun times(v: Vec2, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(x, y, v.x, v.y, res)
}
fun times(x: Float, y: Float, res: Vec2): Vec2 = res(this.x * x, this.y * y)
inline fun times(x: Float, y: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(x, y, x, y, res)
}
operator fun times(m: Mat2): Vec2 = times(m, Vec2())
fun times(m: Mat2, res: Vec2): Vec2 = res(x * m.a0 + y * m.a1,
x * m.b0 + y * m.b1)
inline fun times(m: Mat2, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(m.a0, m.a1,
m.b0, m.b1, res)
}
inline fun times(a0: Float, a1: Float,
b0: Float, b1: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(x * a0 + y * a1,
x * b0 + y * b1)
}
operator fun times(m: Mat3x2): Vec3 = times(m, Vec3())
fun times(m: Mat3x2, res: Vec3): Vec3 = res(x * m.a0 + y * m.a1,
x * m.b0 + y * m.b1,
x * m.c0 + y * m.c1)
inline fun times(m: Mat3x2, res: (resX: Float, resY: Float, resZ: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(m.a0, m.a1,
m.b0, m.b1,
m.c0, m.c1, res)
}
inline fun times(a0: Float, a1: Float,
b0: Float, b1: Float,
c0: Float, c1: Float, res: (resX: Float, resY: Float, resZ: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(x * a0 + y * a1,
x * b0 + y * b1,
x * c0 + y * c1)
}
operator fun times(m: Mat4x2): Vec4 = times(m, Vec4())
fun times(m: Mat4x2, res: Vec4): Vec4 = res(x * m.a0 + y * m.a1,
x * m.b0 + y * m.b1,
x * m.c0 + y * m.c1,
x * m.d0 + y * m.d1)
inline fun times(m: Mat4x2, res: (resX: Float, resY: Float, resZ: Float, resW: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
times(m.a0, m.a1,
m.b0, m.b1,
m.c0, m.c1,
m.d0, m.d1, res)
}
inline fun times(a0: Float, a1: Float,
b0: Float, b1: Float,
c0: Float, c1: Float,
d0: Float, d1: Float, res: (resX: Float, resY: Float, resZ: Float, resW: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(x * a0 + y * a1,
x * b0 + y * b1,
x * c0 + y * c1,
x * d0 + y * d1)
}
operator fun div(scalar: Float): Vec2 = div(scalar, scalar, Vec2())
fun div(scalar: Float, res: Vec2): Vec2 = div(scalar, scalar, res)
inline fun div(scalar: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
div(x, y, scalar, scalar, res)
}
operator fun div(v: Vec1): Vec2 = div(v.x, v.x, Vec2())
fun div(v: Vec1, res: Vec2): Vec2 = div(v.x, v.x, res)
inline fun div(v: Vec1, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
div(x, y, v.x, v.x, res)
}
operator fun div(v: Vec2): Vec2 = div(v.x, v.y, Vec2())
fun div(v: Vec2, res: Vec2): Vec2 = div(v.x, v.y, res)
inline fun div(v: Vec2, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
div(x, y, v.x, v.y, res)
}
fun div(x: Float, y: Float, res: Vec2): Vec2 = res(this.x / x, this.y / y)
inline fun div(x: Float, y: Float, res: (resX: Float, resY: Float) -> Unit) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
div(x, y, x, y, res)
}
operator fun div(m: Mat2): Vec2 = div(m, Vec2())
fun div(m: Mat2, res: Vec2): Vec2 {
val oneOverDeterminant = 1f / (
+ m.a0 * m.b1
- m.b0 * m.a1)
val i00 = + m.b1 * oneOverDeterminant
val i01 = - m.a1 * oneOverDeterminant
val i10 = - m.b0 * oneOverDeterminant
val i11 = + m.a0 * oneOverDeterminant
return res(x * i00 + y * i01,
x * i10 + y * i11)
}
// geometric
/**
* Returns the dot product of this [Vec2] and [b], i.e., `result = this * b`.
* @see [GLSL dot man page](http://www.opengl.org/sdk/docs/manglsl/xhtml/dot.xml)
* @see [GLSL 4.20.8 specification, section 8.5 Geometric Functions](http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf)
*/
infix fun dot(b: Vec2): Float {
val x: Float; val y: Float
times(b) { resX, resY -> x = resX; y = resY }
return x + y
}
/**
* Returns the length of this [Vec2], i.e., `sqrt(this * this)`.
* @see [GLSL length man page](http://www.opengl.org/sdk/docs/manglsl/xhtml/length.xml)
* @see [GLSL 4.20.8 specification, section 8.5 Geometric Functions](http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf)
*/
fun length(): Float = sqrt(this dot this)
// Dot products
@JvmName("dotUByte")
infix fun dot(v: Vec2T<UByte>) = (x * v.x.f + y * v.y.f).f
@JvmName("dotUShort")
infix fun dot(v: Vec2T<UShort>) = (x * v.x.f + y * v.y.f).f
@JvmName("dotUInt")
infix fun dot(v: Vec2T<UInt>) = (x * v.x.f + y * v.y.f).f
@JvmName("dotULong")
infix fun dot(v: Vec2T<ULong>) = (x * v.x.f + y * v.y.f).f
infix fun dot(v: Vec2T<out Number>) = (x * v.x.f + y * v.y.f).f
override fun equals(other: Any?) = other is Vec2 && x == other.x && y == other.y
override fun hashCode() = 1 * x.hashCode() + 31 * y.hashCode()
fun equal(v: Vec2, epsilon: Float = Float.MIN_VALUE) = BooleanArray(length) { abs(array[it] - v.array[it]) <= epsilon }
fun notEqual(v: Vec2, epsilon: Float = Float.MIN_VALUE) = BooleanArray(length) { abs(array[it] - v.array[it]) > epsilon }
fun allEqual(v: Vec2, epsilon: Float = Float.MIN_VALUE): Boolean {
for (i in 0 until length)
if(abs(array[i] - v.array[i]) > epsilon)
return false
return true
}
fun anyNotEqual(v: Vec2, epsilon: Float = Float.MIN_VALUE): Boolean {
for (i in 0 until length)
if(abs(array[i] - v.array[i]) > epsilon)
return true
return false
}
companion object {
const val length = Vec2T.length
const val size = length * Float.SIZE_BYTES
inline fun plus(aX: Float, aY: Float,
bX: Float, bY: Float, res:(resX: Float, resY: Float) -> Unit ) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(aX + bX, aY + bY)
}
inline fun minus(aX: Float, aY: Float,
bX: Float, bY: Float, res:(resX: Float, resY: Float) -> Unit ) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(aX - bX, aY - bY)
}
inline fun times(aX: Float, aY: Float,
bX: Float, bY: Float, res:(resX: Float, resY: Float) -> Unit ) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(aX * bX, aY * bY)
}
inline fun div(aX: Float, aY: Float,
bX: Float, bY: Float, res:(resX: Float, resY: Float) -> Unit ) {
kotlin.contracts.contract { callsInPlace(res, kotlin.contracts.InvocationKind.EXACTLY_ONCE) }
res(aX / bX, aY / bY)
}
}
}
// Binary operators
operator fun Float.plus(v: Vec2) = Vec2(this + v.x, this + v.y)
operator fun Vec1.plus(v: Vec2) = Vec2(x + v.x, x + v.y)
operator fun Float.minus(v: Vec2) = Vec2(this - v.x, this - v.y)
operator fun Vec1.minus(v: Vec2) = Vec2(x - v.x, x - v.y)
operator fun Float.times(v: Vec2) = Vec2(this * v.x, this * v.y)
operator fun Vec1.times(v: Vec2) = Vec2(x * v.x, x * v.y)
operator fun Float.div(v: Vec2) = Vec2(this / v.x, this / v.y)
operator fun Vec1.div(v: Vec2) = Vec2(x / v.x, x / v.y)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment