Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,44 @@
package iron.math;
import kha.FastFloat;
class Mat3 {
public var self: kha.math.FastMatrix3;
public inline function new(_00: FastFloat, _10: FastFloat, _20: FastFloat,
_01: FastFloat, _11: FastFloat, _21: FastFloat,
_02: FastFloat, _12: FastFloat, _22: FastFloat) {
self = new kha.math.FastMatrix3(_00, _10, _20, _01, _11, _21, _02, _12, _22);
}
public static inline function identity(): Mat3 {
return new Mat3(
1, 0, 0,
0, 1, 0,
0, 0, 1
);
}
public inline function setFrom4(m: Mat4) {
_00 = m._00;
_01 = m._01;
_02 = m._02;
_10 = m._10;
_11 = m._11;
_12 = m._12;
_20 = m._20;
_21 = m._21;
_22 = m._22;
}
public var _00(get, set): FastFloat; inline function get__00(): FastFloat { return self._00; } inline function set__00(f: FastFloat): FastFloat { return self._00 = f; }
public var _01(get, set): FastFloat; inline function get__01(): FastFloat { return self._01; } inline function set__01(f: FastFloat): FastFloat { return self._01 = f; }
public var _02(get, set): FastFloat; inline function get__02(): FastFloat { return self._02; } inline function set__02(f: FastFloat): FastFloat { return self._02 = f; }
public var _10(get, set): FastFloat; inline function get__10(): FastFloat { return self._10; } inline function set__10(f: FastFloat): FastFloat { return self._10 = f; }
public var _11(get, set): FastFloat; inline function get__11(): FastFloat { return self._11; } inline function set__11(f: FastFloat): FastFloat { return self._11 = f; }
public var _12(get, set): FastFloat; inline function get__12(): FastFloat { return self._12; } inline function set__12(f: FastFloat): FastFloat { return self._12 = f; }
public var _20(get, set): FastFloat; inline function get__20(): FastFloat { return self._20; } inline function set__20(f: FastFloat): FastFloat { return self._20 = f; }
public var _21(get, set): FastFloat; inline function get__21(): FastFloat { return self._21; } inline function set__21(f: FastFloat): FastFloat { return self._21 = f; }
public var _22(get, set): FastFloat; inline function get__22(): FastFloat { return self._22; } inline function set__22(f: FastFloat): FastFloat { return self._22 = f; }
}

View File

@ -0,0 +1,619 @@
package iron.math;
import kha.FastFloat;
class Mat4 {
public var self: kha.math.FastMatrix4;
static var helpVec = new Vec4();
static var helpMat = Mat4.identity();
public inline function new(_00: FastFloat, _10: FastFloat, _20: FastFloat, _30: FastFloat,
_01: FastFloat, _11: FastFloat, _21: FastFloat, _31: FastFloat,
_02: FastFloat, _12: FastFloat, _22: FastFloat, _32: FastFloat,
_03: FastFloat, _13: FastFloat, _23: FastFloat, _33: FastFloat) {
self = new kha.math.FastMatrix4(_00, _10, _20, _30, _01, _11, _21, _31, _02, _12, _22, _32, _03, _13, _23, _33);
}
/**
Set the transform from a location, rotation and scale.
@param loc The location to use.
@param quat The rotation to use.
@param sc The scale to use.
@return This matrix.
**/
public inline function compose(loc: Vec4, quat: Quat, sc: Vec4): Mat4 {
fromQuat(quat);
scale(sc);
setLoc(loc);
return this;
}
/**
Decompose this matrix into its location, rotation and scale components.
Additional transforms (skew, projection) will be ignored.
@param loc A vector to write the location to.
@param quat A quaternion to write the rotation to.
@param scale A vector to write the scale to.
@return This matrix.
**/
public inline function decompose(loc: Vec4, quat: Quat, scale: Vec4): Mat4 {
loc.x = _30; loc.y = _31; loc.z = _32;
scale.x = helpVec.set(_00, _01, _02).length();
scale.y = helpVec.set(_10, _11, _12).length();
scale.z = helpVec.set(_20, _21, _22).length();
if (self.determinant() < 0.0) scale.x = -scale.x;
var invs = 1.0 / scale.x; // Scale the rotation part
helpMat._00 = _00 * invs;
helpMat._01 = _01 * invs;
helpMat._02 = _02 * invs;
invs = 1.0 / scale.y;
helpMat._10 = _10 * invs;
helpMat._11 = _11 * invs;
helpMat._12 = _12 * invs;
invs = 1.0 / scale.z;
helpMat._20 = _20 * invs;
helpMat._21 = _21 * invs;
helpMat._22 = _22 * invs;
quat.fromRotationMat(helpMat);
return this;
}
/**
Set the location component of this matrix.
@param v The location to use.
@return This matrix.
**/
public inline function setLoc(v: Vec4): Mat4 {
_30 = v.x;
_31 = v.y;
_32 = v.z;
return this;
}
/**
Set the transform to a rotation from a quaternion. Other existing
transforms will be removed.
@param q The rotation to use.
@return This matrix.
**/
public inline function fromQuat(q: Quat): Mat4 {
var x = q.x; var y = q.y; var z = q.z; var w = q.w;
var x2 = x + x; var y2 = y + y; var z2 = z + z;
var xx = x * x2; var xy = x * y2; var xz = x * z2;
var yy = y * y2; var yz = y * z2; var zz = z * z2;
var wx = w * x2; var wy = w * y2; var wz = w * z2;
_00 = 1.0 - (yy + zz);
_10 = xy - wz;
_20 = xz + wy;
_01 = xy + wz;
_11 = 1.0 - (xx + zz);
_21 = yz - wx;
_02 = xz - wy;
_12 = yz + wx;
_22 = 1.0 - (xx + yy);
_03 = 0.0;
_13 = 0.0;
_23 = 0.0;
_30 = 0.0;
_31 = 0.0;
_32 = 0.0;
_33 = 1.0;
return this;
}
/**
Set all components of this matrix from an array.
@param a The 16-component array to use. Components should be in the
same order as for `Mat4.new()`.
@param offset An offset index to the start of the data in the array.
Defaults to 0.
@return A new matrix.
**/
public static inline function fromFloat32Array(a: kha.arrays.Float32Array, offset = 0): Mat4 {
return new Mat4(
a[0 + offset], a[1 + offset], a[2 + offset], a[3 + offset],
a[4 + offset], a[5 + offset], a[6 + offset], a[7 + offset],
a[8 + offset], a[9 + offset], a[10 + offset], a[11 + offset],
a[12 + offset], a[13 + offset], a[14 + offset], a[15 + offset]
);
}
/**
Create a matrix that represents no transform - located at the origin,
zero rotation, and a uniform scale of 1.
@return A new matrix.
**/
public static inline function identity(): Mat4 {
return new Mat4(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
}
/**
Set this matrix to the identity (see `identity()`).
@return This matrix.
**/
public inline function setIdentity(): Mat4 {
_00 = 1.0; _01 = 0.0; _02 = 0.0; _03 = 0.0;
_10 = 0.0; _11 = 1.0; _12 = 0.0; _13 = 0.0;
_20 = 0.0; _21 = 0.0; _22 = 1.0; _23 = 0.0;
_30 = 0.0; _31 = 0.0; _32 = 0.0; _33 = 1.0;
return this;
}
/**
Reset this matrix to the identity and set its location.
@param x The x location.
@param y The y location.
@param z The z location.
@return This matrix.
**/
public inline function initTranslate(x: FastFloat = 0.0, y: FastFloat = 0.0, z: FastFloat = 0.0): Mat4 {
_00 = 1.0; _01 = 0.0; _02 = 0.0; _03 = 0.0;
_10 = 0.0; _11 = 1.0; _12 = 0.0; _13 = 0.0;
_20 = 0.0; _21 = 0.0; _22 = 1.0; _23 = 0.0;
_30 = x; _31 = y; _32 = z; _33 = 1.0;
return this;
}
/**
Apply an additional translation to this matrix.
@param x The distance to move in the x direction.
@param y The distance to move in the x direction.
@param z The distance to move in the x direction.
@return This matrix
**/
public inline function translate(x: FastFloat, y: FastFloat, z: FastFloat): Mat4 {
_00 += x * _03; _01 += y * _03; _02 += z * _03;
_10 += x * _13; _11 += y * _13; _12 += z * _13;
_20 += x * _23; _21 += y * _23; _22 += z * _23;
_30 += x * _33; _31 += y * _33; _32 += z * _33;
return this;
}
/**
Apply an additional scale to this matrix.
@param v The vector to scale by.
@return This matrix.
**/
public inline function scale(v: Vec4): Mat4 {
var x = v.x; var y = v.y; var z = v.z;
_00 *= x;
_01 *= x;
_02 *= x;
_03 *= x;
_10 *= y;
_11 *= y;
_12 *= y;
_13 *= y;
_20 *= z;
_21 *= z;
_22 *= z;
_23 *= z;
return this;
}
public inline function multmats3x4(a: Mat4, b: Mat4): Mat4 {
var a00 = a._00; var a01 = a._01; var a02 = a._02; var a03 = a._03;
var a10 = a._10; var a11 = a._11; var a12 = a._12; var a13 = a._13;
var a20 = a._20; var a21 = a._21; var a22 = a._22; var a23 = a._23;
var a30 = a._30; var a31 = a._31; var a32 = a._32; var a33 = a._33;
var b0 = b._00; var b1 = b._10; var b2 = b._20; var b3 = b._30;
_00 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_10 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_20 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_30 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b._01; b1 = b._11; b2 = b._21; b3 = b._31;
_01 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_11 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_21 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_31 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b._02; b1 = b._12; b2 = b._22; b3 = b._32;
_02 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_12 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_22 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_32 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
_03 = 0;
_13 = 0;
_23 = 0;
_33 = 1;
return this;
}
public inline function multmats(b: Mat4, a: Mat4): Mat4 {
var a00 = a._00; var a01 = a._01; var a02 = a._02; var a03 = a._03;
var a10 = a._10; var a11 = a._11; var a12 = a._12; var a13 = a._13;
var a20 = a._20; var a21 = a._21; var a22 = a._22; var a23 = a._23;
var a30 = a._30; var a31 = a._31; var a32 = a._32; var a33 = a._33;
var b0 = b._00; var b1 = b._10; var b2 = b._20; var b3 = b._30;
_00 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_10 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_20 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_30 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b._01; b1 = b._11; b2 = b._21; b3 = b._31;
_01 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_11 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_21 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_31 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b._02; b1 = b._12; b2 = b._22; b3 = b._32;
_02 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_12 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_22 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_32 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b._03; b1 = b._13; b2 = b._23; b3 = b._33;
_03 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_13 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_23 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_33 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
return this;
}
public inline function multmat(m: Mat4): Mat4 {
var a00 = _00; var a01 = _01; var a02 = _02; var a03 = _03;
var a10 = _10; var a11 = _11; var a12 = _12; var a13 = _13;
var a20 = _20; var a21 = _21; var a22 = _22; var a23 = _23;
var a30 = _30; var a31 = _31; var a32 = _32; var a33 = _33;
var b0 = m._00; var b1 = m._10; var b2 = m._20; var b3 = m._30;
_00 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_10 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_20 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_30 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = m._01; b1 = m._11; b2 = m._21; b3 = m._31;
_01 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_11 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_21 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_31 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = m._02; b1 = m._12; b2 = m._22; b3 = m._32;
_02 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_12 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_22 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_32 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = m._03; b1 = m._13; b2 = m._23; b3 = m._33;
_03 = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
_13 = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
_23 = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
_33 = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
return this;
}
/**
Invert a matrix and store the result in this one.
@param m The matrix to invert.
@return This matrix.
**/
public inline function getInverse(m: Mat4): Mat4 {
var a00 = m._00; var a01 = m._01; var a02 = m._02; var a03 = m._03;
var a10 = m._10; var a11 = m._11; var a12 = m._12; var a13 = m._13;
var a20 = m._20; var a21 = m._21; var a22 = m._22; var a23 = m._23;
var a30 = m._30; var a31 = m._31; var a32 = m._32; var a33 = m._33;
var b00 = a00 * a11 - a01 * a10;
var b01 = a00 * a12 - a02 * a10;
var b02 = a00 * a13 - a03 * a10;
var b03 = a01 * a12 - a02 * a11;
var b04 = a01 * a13 - a03 * a11;
var b05 = a02 * a13 - a03 * a12;
var b06 = a20 * a31 - a21 * a30;
var b07 = a20 * a32 - a22 * a30;
var b08 = a20 * a33 - a23 * a30;
var b09 = a21 * a32 - a22 * a31;
var b10 = a21 * a33 - a23 * a31;
var b11 = a22 * a33 - a23 * a32;
var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (det == 0.0) return setIdentity();
det = 1.0 / det;
_00 = (a11 * b11 - a12 * b10 + a13 * b09) * det;
_01 = (a02 * b10 - a01 * b11 - a03 * b09) * det;
_02 = (a31 * b05 - a32 * b04 + a33 * b03) * det;
_03 = (a22 * b04 - a21 * b05 - a23 * b03) * det;
_10 = (a12 * b08 - a10 * b11 - a13 * b07) * det;
_11 = (a00 * b11 - a02 * b08 + a03 * b07) * det;
_12 = (a32 * b02 - a30 * b05 - a33 * b01) * det;
_13 = (a20 * b05 - a22 * b02 + a23 * b01) * det;
_20 = (a10 * b10 - a11 * b08 + a13 * b06) * det;
_21 = (a01 * b08 - a00 * b10 - a03 * b06) * det;
_22 = (a30 * b04 - a31 * b02 + a33 * b00) * det;
_23 = (a21 * b02 - a20 * b04 - a23 * b00) * det;
_30 = (a11 * b07 - a10 * b09 - a12 * b06) * det;
_31 = (a00 * b09 - a01 * b07 + a02 * b06) * det;
_32 = (a31 * b01 - a30 * b03 - a32 * b00) * det;
_33 = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return this;
}
/**
Transpose this matrix.
@return This matrix.
**/
public inline function transpose(): Mat4 {
var f = _01; _01 = _10; _10 = f;
f = _02; _02 = _20; _20 = f;
f = _03; _03 = _30; _30 = f;
f = _12; _12 = _21; _21 = f;
f = _13; _13 = _31; _31 = f;
f = _23; _23 = _32; _32 = f;
return this;
}
public inline function transpose3x3(): Mat4 {
var f = _01; _01 = _10; _10 = f;
f = _02; _02 = _20; _20 = f;
f = _12; _12 = _21; _21 = f;
return this;
}
/**
Create a copy of this matrix.
@return A new matrix.
**/
public inline function clone(): Mat4 {
return new Mat4(
_00, _10, _20, _30,
_01, _11, _21, _31,
_02, _12, _22, _32,
_03, _13, _23, _33
);
}
public inline function setF32(a: kha.arrays.Float32Array, offset = 0): Mat4 {
_00 = a[0 + offset]; _10 = a[1 + offset]; _20 = a[2 + offset]; _30 = a[3 + offset];
_01 = a[4 + offset]; _11 = a[5 + offset]; _21 = a[6 + offset]; _31 = a[7 + offset];
_02 = a[8 + offset]; _12 = a[9 + offset]; _22 = a[10 + offset]; _32 = a[11 + offset];
_03 = a[12 + offset]; _13 = a[13 + offset]; _23 = a[14 + offset]; _33 = a[15 + offset];
return this;
}
public inline function setFrom(m: Mat4): Mat4 {
_00 = m._00; _01 = m._01; _02 = m._02; _03 = m._03;
_10 = m._10; _11 = m._11; _12 = m._12; _13 = m._13;
_20 = m._20; _21 = m._21; _22 = m._22; _23 = m._23;
_30 = m._30; _31 = m._31; _32 = m._32; _33 = m._33;
return this;
}
/**
Get the location component.
@return A new vector.
**/
public inline function getLoc(): Vec4 {
return new Vec4(_30, _31, _32, _33);
}
/**
Get the scale component.
@return A new vector.
**/
public inline function getScale(): Vec4 {
return new Vec4(
Math.sqrt(_00 * _00 + _10 * _10 + _20 * _20),
Math.sqrt(_01 * _01 + _11 * _11 + _21 * _21),
Math.sqrt(_02 * _02 + _12 * _12 + _22 * _22)
);
}
/**
Multiply this vector by a scalar.
@param s The value to multiply by.
@return This matrix.
**/
public inline function mult(s: FastFloat): Mat4 {
_00 *= s; _10 *= s; _20 *= s; _30 *= s;
_01 *= s; _11 *= s; _21 *= s; _31 *= s;
_02 *= s; _12 *= s; _22 *= s; _32 *= s;
_03 *= s; _13 *= s; _23 *= s; _33 *= s;
return this;
}
/**
Convert this matrix to a rotation matrix, and discard location and
scale information.
@return This matrix.
**/
public inline function toRotation(): Mat4 {
var scale = 1.0 / helpVec.set(_00, _01, _02).length();
_00 = _00 * scale;
_01 = _01 * scale;
_02 = _02 * scale;
scale = 1.0 / helpVec.set(_10, _11, _12).length();
_10 = _10 * scale;
_11 = _11 * scale;
_12 = _12 * scale;
scale = 1.0 / helpVec.set(_20, _21, _22).length();
_20 = _20 * scale;
_21 = _21 * scale;
_22 = _22 * scale;
_03 = 0.0;
_13 = 0.0;
_23 = 0.0;
_30 = 0.0;
_31 = 0.0;
_32 = 0.0;
_33 = 1.0;
return this;
}
/**
Create a new perspective projection matrix.
@param fovY The vertical field of view.
@param aspect The aspect ratio.
@param zn The depth of the near floor of the frustum.
@param zf The depth of the far floor of the frustum.
@return A new matrix.
**/
public static inline function persp(fovY: FastFloat, aspect: FastFloat, zn: FastFloat, zf: FastFloat): Mat4 {
var uh = 1.0 / Math.tan(fovY / 2);
var uw = uh / aspect;
return new Mat4(
uw, 0, 0, 0,
0, uh, 0, 0,
0, 0, (zf + zn) / (zn - zf), 2 * zf * zn / (zn - zf),
0, 0, -1, 0
);
}
/**
Create a new orthographic projection matrix.
@param left The left of the box.
@param right The right of the box.
@param bottom The bottom of the box.
@param top The top of the box.
@param near The depth of the near floor of the box.
@param far The depth of the far floor of the box.
@return A new matrix.
**/
public static inline function ortho(left: FastFloat, right: FastFloat, bottom: FastFloat, top: FastFloat, near: FastFloat, far: FastFloat): Mat4 {
var rl = right - left;
var tb = top - bottom;
var fn = far - near;
var tx = -(right + left) / (rl);
var ty = -(top + bottom) / (tb);
var tz = -(far + near) / (fn);
return new Mat4(
2 / rl, 0, 0, tx,
0, 2 / tb, 0, ty,
0, 0, -2 / fn, tz,
0, 0, 0, 1
);
}
public inline function setLookAt(eye: Vec4, center: Vec4, up: Vec4): Mat4 {
var f0 = center.x - eye.x;
var f1 = center.y - eye.y;
var f2 = center.z - eye.z;
var n = 1.0 / Math.sqrt(f0 * f0 + f1 * f1 + f2 * f2);
f0 *= n;
f1 *= n;
f2 *= n;
var s0 = f1 * up.z - f2 * up.y;
var s1 = f2 * up.x - f0 * up.z;
var s2 = f0 * up.y - f1 * up.x;
n = 1.0 / Math.sqrt(s0 * s0 + s1 * s1 + s2 * s2);
s0 *= n;
s1 *= n;
s2 *= n;
var u0 = s1 * f2 - s2 * f1;
var u1 = s2 * f0 - s0 * f2;
var u2 = s0 * f1 - s1 * f0;
var d0 = -eye.x * s0 - eye.y * s1 - eye.z * s2;
var d1 = -eye.x * u0 - eye.y * u1 - eye.z * u2;
var d2 = eye.x * f0 + eye.y * f1 + eye.z * f2;
_00 = s0;
_10 = s1;
_20 = s2;
_30 = d0;
_01 = u0;
_11 = u1;
_21 = u2;
_31 = d1;
_02 = -f0;
_12 = -f1;
_22 = -f2;
_32 = d2;
_03 = 0.0;
_13 = 0.0;
_23 = 0.0;
_33 = 1.0;
return this;
}
/**
Apply an additional rotation to this matrix.
@param q The quaternion to rotate by.
**/
public inline function applyQuat(q: Quat) {
helpMat.fromQuat(q);
multmat(helpMat);
}
/**
@return The right vector; the positive x axis of the space defined by
this matrix.
**/
public inline function right(): Vec4 {
return new Vec4(_00, _01, _02);
}
/**
@return The look vector; the positive y axis of the space defined by
this matrix.
**/
public inline function look(): Vec4 {
return new Vec4(_10, _11, _12);
}
/**
@return The up vector; the positive z axis of the space defined by
this matrix.
**/
public inline function up(): Vec4 {
return new Vec4(_20, _21, _22);
}
public var _00(get, set): FastFloat; inline function get__00(): FastFloat { return self._00; } inline function set__00(f: FastFloat): FastFloat { return self._00 = f; }
public var _01(get, set): FastFloat; inline function get__01(): FastFloat { return self._01; } inline function set__01(f: FastFloat): FastFloat { return self._01 = f; }
public var _02(get, set): FastFloat; inline function get__02(): FastFloat { return self._02; } inline function set__02(f: FastFloat): FastFloat { return self._02 = f; }
public var _03(get, set): FastFloat; inline function get__03(): FastFloat { return self._03; } inline function set__03(f: FastFloat): FastFloat { return self._03 = f; }
public var _10(get, set): FastFloat; inline function get__10(): FastFloat { return self._10; } inline function set__10(f: FastFloat): FastFloat { return self._10 = f; }
public var _11(get, set): FastFloat; inline function get__11(): FastFloat { return self._11; } inline function set__11(f: FastFloat): FastFloat { return self._11 = f; }
public var _12(get, set): FastFloat; inline function get__12(): FastFloat { return self._12; } inline function set__12(f: FastFloat): FastFloat { return self._12 = f; }
public var _13(get, set): FastFloat; inline function get__13(): FastFloat { return self._13; } inline function set__13(f: FastFloat): FastFloat { return self._13 = f; }
public var _20(get, set): FastFloat; inline function get__20(): FastFloat { return self._20; } inline function set__20(f: FastFloat): FastFloat { return self._20 = f; }
public var _21(get, set): FastFloat; inline function get__21(): FastFloat { return self._21; } inline function set__21(f: FastFloat): FastFloat { return self._21 = f; }
public var _22(get, set): FastFloat; inline function get__22(): FastFloat { return self._22; } inline function set__22(f: FastFloat): FastFloat { return self._22 = f; }
public var _23(get, set): FastFloat; inline function get__23(): FastFloat { return self._23; } inline function set__23(f: FastFloat): FastFloat { return self._23 = f; }
public var _30(get, set): FastFloat; inline function get__30(): FastFloat { return self._30; } inline function set__30(f: FastFloat): FastFloat { return self._30 = f; }
public var _31(get, set): FastFloat; inline function get__31(): FastFloat { return self._31; } inline function set__31(f: FastFloat): FastFloat { return self._31 = f; }
public var _32(get, set): FastFloat; inline function get__32(): FastFloat { return self._32; } inline function set__32(f: FastFloat): FastFloat { return self._32 = f; }
public var _33(get, set): FastFloat; inline function get__33(): FastFloat { return self._33; } inline function set__33(f: FastFloat): FastFloat { return self._33 = f; }
public function toString(): String {
return '[[$_00, $_10, $_20, $_30], [$_01, $_11, $_21, $_31], [$_02, $_12, $_22, $_32], [$_03, $_13, $_23, $_33]]';
}
public function toFloat32Array(): kha.arrays.Float32Array {
var array = new kha.arrays.Float32Array(16);
array[0] = _00;
array[1] = _10;
array[2] = _20;
array[3] = _30;
array[4] = _01;
array[5] = _11;
array[6] = _21;
array[7] = _31;
array[8] = _02;
array[9] = _12;
array[10] = _22;
array[11] = _32;
array[12] = _03;
array[13] = _13;
array[14] = _23;
array[15] = _33;
return array;
}
}

View File

@ -0,0 +1,499 @@
package iron.math;
import kha.FastFloat;
class Quat {
public var x: FastFloat;
public var y: FastFloat;
public var z: FastFloat;
public var w: FastFloat;
static var helpVec0 = new Vec4();
static var helpVec1 = new Vec4();
static var helpVec2 = new Vec4();
static var helpMat = Mat4.identity();
static var xAxis = Vec4.xAxis();
static var yAxis = Vec4.yAxis();
static inline var SQRT2: FastFloat = 1.4142135623730951;
public inline function new(x: FastFloat = 0.0, y: FastFloat = 0.0, z: FastFloat = 0.0, w: FastFloat = 1.0) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
public inline function set(x: FastFloat, y: FastFloat, z: FastFloat, w: FastFloat): Quat {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
}
public inline function add(q: Quat): Quat {
this.x += q.x;
this.y += q.y;
this.z += q.z;
this.w += q.w;
return this;
}
public inline function addquat(a: Quat, b: Quat): Quat {
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
this.w = a.w + b.w;
return this;
}
public inline function sub(q: Quat): Quat {
this.x -= q.x;
this.y -= q.y;
this.z -= q.z;
this.w -= q.w;
return this;
}
public inline function subquat(a: Quat, b: Quat): Quat {
this.x = a.x - b.x;
this.y = a.y - b.y;
this.z = a.z - b.z;
this.w = a.w - b.w;
return this;
}
public inline function fromAxisAngle(axis: Vec4, angle: FastFloat): Quat {
var s: FastFloat = Math.sin(angle * 0.5);
x = axis.x * s;
y = axis.y * s;
z = axis.z * s;
w = Math.cos(angle * 0.5);
return normalize();
}
public inline function toAxisAngle(axis: Vec4): FastFloat {
normalize();
var angle = 2 * Math.acos(w);
var s = Math.sqrt(1 - w * w);
if (s < 0.001) {
axis.x = this.x;
axis.y = this.y;
axis.z = this.z;
}
else {
axis.x = this.x / s;
axis.y = this.y / s;
axis.z = this.z / s;
}
return angle;
}
public inline function fromMat(m: Mat4): Quat {
helpMat.setFrom(m);
helpMat.toRotation();
return fromRotationMat(helpMat);
}
public inline function fromRotationMat(m: Mat4): Quat {
// Assumes the upper 3x3 is a pure rotation matrix
var m11 = m._00; var m12 = m._10; var m13 = m._20;
var m21 = m._01; var m22 = m._11; var m23 = m._21;
var m31 = m._02; var m32 = m._12; var m33 = m._22;
var tr = m11 + m22 + m33;
var s = 0.0;
if (tr > 0) {
s = 0.5 / Math.sqrt(tr + 1.0);
this.w = 0.25 / s;
this.x = (m32 - m23) * s;
this.y = (m13 - m31) * s;
this.z = (m21 - m12) * s;
}
else if (m11 > m22 && m11 > m33) {
s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
this.w = (m32 - m23) / s;
this.x = 0.25 * s;
this.y = (m12 + m21) / s;
this.z = (m13 + m31) / s;
}
else if (m22 > m33) {
s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
this.w = (m13 - m31) / s;
this.x = (m12 + m21) / s;
this.y = 0.25 * s;
this.z = (m23 + m32) / s;
}
else {
s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
this.w = (m21 - m12) / s;
this.x = (m13 + m31) / s;
this.y = (m23 + m32) / s;
this.z = 0.25 * s;
}
return this;
}
// Multiply this quaternion by float
public inline function scale(scale: FastFloat): Quat {
this.x *= scale;
this.y *= scale;
this.z *= scale;
this.w *= scale;
return this;
}
public inline function scalequat(q: Quat, scale: FastFloat): Quat {
q.x *= scale;
q.y *= scale;
q.z *= scale;
q.w *= scale;
return q;
}
/**
Multiply this quaternion by another.
@param q The quaternion to multiply this one with.
@return This quaternion.
**/
public inline function mult(q: Quat): Quat {
return multquats(this, q);
}
/**
Multiply two other quaternions and store the result in this one.
@param q1 The first operand.
@param q2 The second operand.
@return This quaternion.
**/
public inline function multquats(q1: Quat, q2: Quat): Quat {
var q1x = q1.x; var q1y = q1.y; var q1z = q1.z; var q1w = q1.w;
var q2x = q2.x; var q2y = q2.y; var q2z = q2.z; var q2w = q2.w;
x = q1x * q2w + q1w * q2x + q1y * q2z - q1z * q2y;
y = q1w * q2y - q1x * q2z + q1y * q2w + q1z * q2x;
z = q1w * q2z + q1x * q2y - q1y * q2x + q1z * q2w;
w = q1w * q2w - q1x * q2x - q1y * q2y - q1z * q2z;
return this;
}
public inline function module(): FastFloat {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
}
/**
Scale this quaternion to have a magnitude of 1.
@return This quaternion.
**/
public inline function normalize(): Quat {
var l = Math.sqrt(x * x + y * y + z * z + w * w);
if (l == 0.0) {
x = 0;
y = 0;
z = 0;
w = 0;
}
else {
l = 1.0 / l;
x *= l;
y *= l;
z *= l;
w *= l;
}
return this;
}
/**
Invert the given quaternion and store the result in this one.
@param q Quaternion to invert.
@return This quaternion.
**/
public inline function inverse(q: Quat): Quat {
var sqsum = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
sqsum = -1 / sqsum;
x = q.x * sqsum;
y = q.y * sqsum;
z = q.z * sqsum;
w = -q.w * sqsum;
return this;
}
/**
Copy the rotation of another quaternion to this one.
@param q A quaternion to copy.
@return This quaternion.
**/
public inline function setFrom(q: Quat): Quat {
x = q.x;
y = q.y;
z = q.z;
w = q.w;
return this;
}
/**
Convert this quaternion to a YZX Euler (note: XZY in blender order terms).
@return A new YZX Euler that represents the same rotation as this
quaternion.
**/
public inline function getEuler(): Vec4 {
var a = -2 * (x * z - w * y);
var b = w * w + x * x - y * y - z * z;
var c = 2 * (x * y + w * z);
var d = -2 * (y * z - w * x);
var e = w * w - x * x + y * y - z * z;
return new Vec4(Math.atan2(d, e), Math.atan2(a, b), Math.asin(c));
}
/**
Set this quaternion to the rotation represented by a YZX Euler (XZY in blender terms).
@param x The Euler's x component.
@param y The Euler's y component.
@param z The Euler's z component.
@return This quaternion.
**/
public inline function fromEuler(x: FastFloat, y: FastFloat, z: FastFloat): Quat {
var f = x / 2;
var c1 = Math.cos(f);
var s1 = Math.sin(f);
f = y / 2;
var c2 = Math.cos(f);
var s2 = Math.sin(f);
f = z / 2;
var c3 = Math.cos(f);
var s3 = Math.sin(f);
// YZX
this.x = s1 * c2 * c3 + c1 * s2 * s3;
this.y = c1 * s2 * c3 + s1 * c2 * s3;
this.z = c1 * c2 * s3 - s1 * s2 * c3;
this.w = c1 * c2 * c3 - s1 * s2 * s3;
return this;
}
/**
Convert this quaternion to an Euler of arbitrary order.
@param the order of the euler to obtain
(in blender order, opposite from mathematical order)
can be "XYZ", "XZY", "YXZ", "YZX", "ZXY", or "ZYX".
@return A new YZX Euler that represents the same rotation as this
quaternion.
**/
// this method use matrices as a middle ground
// (and is copied from blender's internal code in mathutils)
// note: there are two possible eulers for the same rotation, blender defines the 'best' as the one with the smallest sum of absolute components
// should we actually make that choice, or is just getting one of them randomly good?
// note2: it seems that this engine transforms a vector by using vector×matrix instead of matrix×vector, meaning that the outer transformations are on the RIGHT.
// (…Except for quaternions, where the outer quaternions are on the LEFT.)
// anywho, the way the elements of the matrix are ordered makes sense (first digit-> row ID, second digit->column ID) in this system.
public inline function toEulerOrdered(p: String): Vec4{
// normalize quat ?
var q0: FastFloat = SQRT2 * this.w;
var q1: FastFloat = SQRT2 * this.x;
var q2: FastFloat = SQRT2 * this.y;
var q3: FastFloat = SQRT2 * this.z;
var qda: FastFloat = q0 * q1;
var qdb: FastFloat = q0 * q2;
var qdc: FastFloat = q0 * q3;
var qaa: FastFloat = q1 * q1;
var qab: FastFloat = q1 * q2;
var qac: FastFloat = q1 * q3;
var qbb: FastFloat = q2 * q2;
var qbc: FastFloat = q2 * q3;
var qcc: FastFloat = q3 * q3;
var m = new Mat3(
// OK, *this* matrix is transposed with respect to what leenkx expects.
// it is transposed again in the next step though
(1.0 - qbb - qcc),
(qdc + qab),
(-qdb + qac),
(-qdc + qab),
(1.0 - qaa - qcc),
(qda + qbc),
(qdb + qac),
(-qda + qbc),
(1.0 - qaa - qbb)
);
// now define what is necessary to perform look-ups in that matrix
var ml: Array<Array<FastFloat>> = [[m._00, m._10, m._20],
[m._01, m._11, m._21],
[m._02, m._12, m._22]];
var eull: Array<FastFloat> = [0, 0, 0];
var i: Int = p.charCodeAt(0) - "X".charCodeAt(0);
var j: Int = p.charCodeAt(1) - "X".charCodeAt(0);
var k: Int = p.charCodeAt(2) - "X".charCodeAt(0);
// now the dumber version (isolating code)
if (p.charAt(0) == "X") i = 0;
else if (p.charAt(0) == "Y") i = 1;
else i = 2;
if (p.charAt(1) == "X") j = 0;
else if (p.charAt(1) == "Y") j = 1;
else j = 2;
if (p.charAt(2) == "X") k = 0;
else if (p.charAt(2) == "Y") k = 1;
else k = 2;
var cy: FastFloat = Math.sqrt(ml[i][i] * ml[i][i] + ml[i][j] * ml[i][j]);
var eul1 = new Vec4();
if (cy > 16.0 * 1e-3) {
eull[i] = Math.atan2(ml[j][k], ml[k][k]);
eull[j] = Math.atan2(-ml[i][k], cy);
eull[k] = Math.atan2(ml[i][j], ml[i][i]);
}
else {
eull[i] = Math.atan2(-ml[k][j], ml[j][j]);
eull[j] = Math.atan2(-ml[i][k], cy);
eull[k] = 0; // 2 * Math.PI;
}
eul1.x = eull[0];
eul1.y = eull[1];
eul1.z = eull[2];
if (p == "XZY" || p == "YXZ" || p == "ZYX") {
eul1.x *= -1;
eul1.y *= -1;
eul1.z *= -1;
}
return eul1;
}
/**
Set this quaternion to the rotation represented by an Euler.
@param x The Euler's x component.
@param y The Euler's y component.
@param z The Euler's z component.
@param order: the (blender) order of the euler
(which is the OPPOSITE of the mathematical order)
can be "XYZ", "XZY", "YXZ", "YZX", "ZXY", or "ZYX".
@return This quaternion.
**/
public inline function fromEulerOrdered(e: Vec4, order: String): Quat {
var c1 = Math.cos(e.x / 2);
var c2 = Math.cos(e.y / 2);
var c3 = Math.cos(e.z / 2);
var s1 = Math.sin(e.x / 2);
var s2 = Math.sin(e.y / 2);
var s3 = Math.sin(e.z / 2);
var qx = new Quat(s1, 0, 0, c1);
var qy = new Quat(0, s2, 0, c2);
var qz = new Quat(0, 0, s3, c3);
if (order.charAt(2) == 'X')
this.setFrom(qx);
else if (order.charAt(2) == 'Y')
this.setFrom(qy);
else
this.setFrom(qz);
if (order.charAt(1) == 'X')
this.mult(qx);
else if (order.charAt(1) == 'Y')
this.mult(qy);
else
this.mult(qz);
if (order.charAt(0) == 'X')
this.mult(qx);
else if (order.charAt(0) == 'Y')
this.mult(qy);
else
this.mult(qz);
return this;
}
/**
Linearly interpolate between two other quaterions, and store the
result in this one. This is not a so-called slerp operation.
@param from The quaterion to interpolate from.
@param to The quaterion to interpolate to.
@param s The amount to interpolate, with 0 being `from` and 1 being
`to`, and 0.5 being half way between the two.
@return This quaternion.
**/
public inline function lerp(from: Quat, to: Quat, s: FastFloat): Quat {
var fromx = from.x;
var fromy = from.y;
var fromz = from.z;
var fromw = from.w;
var dot: FastFloat = from.dot(to);
if (dot < 0.0) {
fromx = -fromx;
fromy = -fromy;
fromz = -fromz;
fromw = -fromw;
}
x = fromx + (to.x - fromx) * s;
y = fromy + (to.y - fromy) * s;
z = fromz + (to.z - fromz) * s;
w = fromw + (to.w - fromw) * s;
return normalize();
}
// Slerp is shorthand for spherical linear interpolation
public inline function slerp(from: Quat, to: Quat, t: FastFloat): Quat {
var epsilon: Float = 0.0005;
var dot = from.dot(to);
if (dot > 1 - epsilon) {
var result: Quat = to.add((from.sub(to)).scale(t));
result.normalize();
return result;
}
if (dot < 0) dot = 0;
if (dot > 1) dot = 1;
var theta0: Float = Math.acos(dot);
var theta: Float = theta0 * t;
var q2: Quat = to.sub(scale(dot));
q2.normalize();
var result: Quat = scale(Math.cos(theta)).add(q2.scale(Math.sin(theta)));
result.normalize();
return result;
}
/**
Find the dot product of this quaternion with another.
@param q The other quaternion.
@return The dot product.
**/
public inline function dot(q: Quat): FastFloat {
return (x * q.x) + (y * q.y) + (z * q.z) + (w * q.w);
}
public inline function fromTo(v1: Vec4, v2: Vec4): Quat {
// Rotation formed by direction vectors
// v1 and v2 should be normalized first
var a = helpVec0;
var dot = v1.dot(v2);
if (dot < -0.999999) {
a.crossvecs(xAxis, v1);
if (a.length() < 0.000001) a.crossvecs(yAxis, v1);
a.normalize();
fromAxisAngle(a, Math.PI);
}
else if (dot > 0.999999) {
set(0, 0, 0, 1);
}
else {
a.crossvecs(v1, v2);
set(a.x, a.y, a.z, 1 + dot);
normalize();
}
return this;
}
public function toString(): String {
return this.x + ", " + this.y + ", " + this.z + ", " + this.w;
}
}

View File

@ -0,0 +1,222 @@
package iron.math;
import kha.FastFloat;
class Ray {
public var origin: Vec4;
public var direction: Vec4;
public function new(origin: Vec4 = null, direction: Vec4 = null) {
this.origin = origin == null ? new Vec4() : origin;
this.direction = direction == null ? new Vec4() : direction;
}
public function at(t: FastFloat): Vec4 {
var result = new Vec4();
return result.setFrom(direction).mult(t).add(origin);
}
public function distanceToPoint(point: Vec4): FastFloat {
var v1 = new Vec4();
var directionDistance = v1.subvecs(point, this.origin).dot(this.direction);
// Point behind the ray
if (directionDistance < 0) {
return this.origin.distanceTo(point);
}
v1.setFrom(this.direction).mult(directionDistance).add(this.origin);
return v1.distanceTo(point);
}
public function intersectsSphere(sphereCenter: Vec4, sphereRadius: FastFloat): Bool {
return distanceToPoint(sphereCenter) <= sphereRadius;
}
public function intersectsPlane(plane: Plane): Bool {
// Check if the ray lies on the plane first
var distToPoint = plane.distanceToPoint(this.origin);
if (distToPoint == 0) return true;
var denominator = plane.normal.dot(this.direction);
if (denominator * distToPoint < 0) return true;
// Ray origin is behind the plane (and is pointing behind it)
return false;
}
public function distanceToPlane(plane: Plane): FastFloat {
var denominator = plane.normal.dot(this.direction);
if (denominator == 0) {
// Line is coplanar, return origin
if (plane.distanceToPoint(this.origin) == 0) {
return 0;
}
// Null is preferable to undefined since undefined means.... it is undefined
return -1;
}
var t = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
// Return if the ray never intersects the plane
return t >= 0 ? t : -1;
}
public function intersectPlane(plane: Plane): Vec4 {
var t = this.distanceToPlane(plane);
if (t == -1) return null;
return this.at(t);
}
public function intersectsBox(center: Vec4, dim: Vec4): Bool {
return this.intersectBox(center, dim) != null;
}
public function intersectBox(center: Vec4, dim: Vec4): Vec4 {
// http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/
var tmin, tmax, tymin, tymax, tzmin, tzmax;
var halfX = dim.x / 2;
var halfY = dim.y / 2;
var halfZ = dim.z / 2;
var boxMinX = center.x - halfX;
var boxMinY = center.y - halfY;
var boxMinZ = center.z - halfZ;
var boxMaxX = center.x + halfX;
var boxMaxY = center.y + halfY;
var boxMaxZ = center.z + halfZ;
var invdirx = 1 / this.direction.x;
var invdiry = 1 / this.direction.y;
var invdirz = 1 / this.direction.z;
var origin = this.origin;
if (invdirx >= 0) {
tmin = (boxMinX - origin.x) * invdirx;
tmax = (boxMaxX - origin.x) * invdirx;
}
else {
tmin = (boxMaxX - origin.x) * invdirx;
tmax = (boxMinX - origin.x) * invdirx;
}
if (invdiry >= 0) {
tymin = (boxMinY - origin.y) * invdiry;
tymax = (boxMaxY - origin.y) * invdiry;
}
else {
tymin = (boxMaxY - origin.y) * invdiry;
tymax = (boxMinY - origin.y) * invdiry;
}
if ((tmin > tymax) || (tymin > tmax)) return null;
// These lines also handle the case where tmin or tmax is NaN
// (result of 0 * Infinity). x !== x returns true if x is NaN
if (tymin > tmin || tmin != tmin) tmin = tymin;
if (tymax < tmax || tmax != tmax) tmax = tymax;
if (invdirz >= 0) {
tzmin = (boxMinZ - origin.z) * invdirz;
tzmax = (boxMaxZ - origin.z) * invdirz;
}
else {
tzmin = (boxMaxZ - origin.z) * invdirz;
tzmax = (boxMinZ - origin.z) * invdirz;
}
if ((tmin > tzmax) || (tzmin > tmax)) return null;
if (tzmin > tmin || tmin != tmin ) tmin = tzmin;
if (tzmax < tmax || tmax != tmax ) tmax = tzmax;
// Return point closest to the ray (positive side)
if (tmax < 0) return null;
return this.at(tmin >= 0 ? tmin : tmax);
}
public function intersectTriangle(a: Vec4, b: Vec4, c: Vec4, backfaceCulling: Bool): Vec4 {
// Compute the offset origin, edges, and normal
var diff = new Vec4();
var edge1 = new Vec4();
var edge2 = new Vec4();
var normal = new Vec4();
// from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp
edge1.subvecs(b, a);
edge2.subvecs(c, a);
normal.crossvecs(edge1, edge2);
// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
var DdN = this.direction.dot(normal);
var sign;
if (DdN > 0) {
if (backfaceCulling) return null;
sign = 1;
}
else if (DdN < 0) {
sign = -1;
DdN = -DdN;
}
else {
return null;
}
diff.subvecs(this.origin, a);
var DdQxE2 = sign * this.direction.dot(edge2.crossvecs(diff, edge2));
// b1 < 0, no intersection
if (DdQxE2 < 0) {
return null;
}
var DdE1xQ = sign * this.direction.dot(edge1.cross(diff));
// b2 < 0, no intersection
if (DdE1xQ < 0) {
return null;
}
// b1+b2 > 1, no intersection
if (DdQxE2 + DdE1xQ > DdN) {
return null;
}
// Line intersects triangle, check if ray does.
var QdN = -sign * diff.dot(normal);
// t < 0, no intersection
if (QdN < 0) {
return null;
}
// Ray intersects triangle.
return this.at(QdN / DdN);
}
}
class Plane {
public var normal = new Vec4(1.0, 0.0, 0.0);
public var constant = 0.0;
public function new() {}
public function distanceToPoint(point: Vec4): FastFloat {
return normal.dot(point) + constant;
}
public function set(normal: Vec4, point: Vec4): Plane {
this.normal.setFrom(normal);
constant = -point.dot(this.normal);
return this;
}
}

View File

@ -0,0 +1,178 @@
package iron.math;
import kha.FastFloat;
import iron.object.CameraObject;
import iron.object.MeshObject;
import iron.object.Transform;
import iron.object.Object;
import iron.math.Ray;
class RayCaster {
static var VPInv = Mat4.identity();
static var PInv = Mat4.identity();
static var VInv = Mat4.identity();
static var loc = new Vec4();
static var nor = new Vec4();
static var m = Mat4.identity();
public static function getRay(inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Ray {
var start = new Vec4();
var end = new Vec4();
getDirection(start, end, inputX, inputY, camera);
// Find direction from start to end
end.sub(start);
end.normalize();
end.x *= camera.data.raw.far_plane;
end.y *= camera.data.raw.far_plane;
end.z *= camera.data.raw.far_plane;
return new Ray(start, end);
}
public static function getDirection(start: Vec4, end: Vec4, inputX: FastFloat, inputY: FastFloat, camera: CameraObject) {
// Get 3D point form screen coords
// Set two vectors with opposing z values
start.x = (inputX / iron.App.w()) * 2.0 - 1.0;
start.y = -((inputY / iron.App.h()) * 2.0 - 1.0);
start.z = -1.0;
end.x = start.x;
end.y = start.y;
end.z = 1.0;
PInv.getInverse(camera.P);
VInv.getInverse(camera.V);
VPInv.multmats(VInv, PInv);
start.applyproj(VPInv);
end.applyproj(VPInv);
}
public static function boxIntersect(transform: Transform, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Vec4 {
var ray = getRay(inputX, inputY, camera);
var t = transform;
var c = new Vec4(t.worldx(), t.worldy(), t.worldz());
var s = new Vec4(t.dim.x, t.dim.y, t.dim.z);
return ray.intersectBox(c, s);
}
public static function boxIntersectObject(o: Object, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Vec4 {
var ray = getRay(inputX, inputY, camera);
var t = o.transform;
var c = new Vec4(t.worldx(), t.worldy(), t.worldz());
var s = new Vec4(t.dim.x, t.dim.y, t.dim.z);
return ray.intersectBox(c, s);
}
public static function closestBoxIntersect(transforms: Array<Transform>, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Transform {
var intersects: Array<Transform> = [];
// Get intersects
for (t in transforms) {
var intersect = boxIntersect(t, inputX, inputY, camera);
if (intersect != null) intersects.push(t);
}
// No intersects
if (intersects.length == 0) return null;
// Get closest intersect
var closest: Transform = null;
var minDist = Math.POSITIVE_INFINITY;
for (t in intersects) {
var dist = Vec4.distance(t.loc, camera.transform.loc);
if (dist < minDist) {
minDist = dist;
closest = t;
}
}
return closest;
}
public static function closestBoxIntersectObject(objects: Array<Object>, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Object {
var intersects: Array<Object> = [];
// Get intersects
for (o in objects) {
var intersect = boxIntersectObject(o, inputX, inputY, camera);
if (intersect != null) intersects.push(o);
}
// No intersects
if (intersects.length == 0) return null;
// Get closest intersect
var closest: Object = null;
var minDist = Math.POSITIVE_INFINITY;
for (t in intersects) {
var dist = Vec4.distance(t.transform.loc, camera.transform.loc);
if (dist < minDist) {
minDist = dist;
closest = t;
}
}
return closest;
}
public static function planeIntersect(normal: Vec4, a: Vec4, inputX: FastFloat, inputY: FastFloat, camera: CameraObject): Vec4 {
var ray = getRay(inputX, inputY, camera);
var plane = new Plane();
plane.set(normal, a);
return ray.intersectPlane(plane);
}
// Project screen-space point onto 3D plane
public static function getPlaneUV(obj: MeshObject, screenX: FastFloat, screenY: FastFloat, camera: CameraObject): Vec2 {
nor = obj.transform.up(); // Transformed normal
// Plane intersection
loc.set(obj.transform.worldx(), obj.transform.worldy(), obj.transform.worldz());
var hit = RayCaster.planeIntersect(nor, loc, screenX, screenY, camera);
// Convert to uv
if (hit != null) {
var normals = obj.data.geom.normals.values;
nor.set(normals[0], normals[1], normals[2]); // Raw normal
var a = nor.x;
var b = nor.y;
var c = nor.z;
var e = 0.0001;
var u = a >= e && b >= e ? new Vec4(b, -a, 0) : new Vec4(c, -a, 0);
u.normalize();
var v = nor.clone();
v.cross(u);
m.setFrom(obj.transform.world);
m.getInverse(m);
m.transpose3x3();
m._30 = m._31 = m._32 = 0;
u.applymat(m);
u.normalize();
v.applymat(m);
v.normalize();
hit.sub(loc); // Center
var ucoord = u.dot(hit);
var vcoord = v.dot(hit);
var dim = obj.transform.dim;
var size = dim.x > dim.y ? dim.x / 2 : dim.y / 2;
// Screen space
var ix = ucoord / size * -0.5 + 0.5;
var iy = vcoord / size * -0.5 + 0.5;
return new Vec2(ix, iy);
}
return null;
}
}

View File

@ -0,0 +1,138 @@
package iron.math;
import kha.FastFloat;
class Vec2 {
public var x: FastFloat;
public var y: FastFloat;
public inline function new(x: FastFloat = 0.0, y: FastFloat = 0.0) {
this.x = x;
this.y = y;
}
public inline function cross(v: Vec2): FastFloat {
return x * v.y - y * v.x;
}
public inline function set(x: FastFloat, y: FastFloat): Vec2{
this.x = x;
this.y = y;
return this;
}
public inline function add(v: Vec2): Vec2 {
x += v.x;
y += v.y;
return this;
}
public inline function addf(x: FastFloat, y: FastFloat): Vec2 {
this.x += x;
this.y += y;
return this;
}
public inline function addvecs(a: Vec2, b: Vec2): Vec2 {
x = a.x + b.x;
y = a.y + b.y;
return this;
}
public inline function subvecs(a: Vec2, b: Vec2): Vec2 {
x = a.x - b.x;
y = a.y - b.y;
return this;
}
public inline function normalize(): Vec2 {
var a = this.x;
var b = this.y;
var l = a * a + b * b;
if (l > 0.0) {
l = 1.0 / Math.sqrt(l);
this.x = a * l;
this.y = b * l;
}
return this;
}
public inline function mult(f: FastFloat): Vec2 {
x *= f;
y *= f;
return this;
}
public inline function dot(v: Vec2): FastFloat {
return x * v.x + y * v.y;
}
public inline function setFrom(v: Vec2): Vec2 {
x = v.x;
y = v.y;
return this;
}
public inline function clone(): Vec2 {
return new Vec2(x, y);
}
public inline function lerp(from: Vec2, to: Vec2, s: FastFloat): Vec2 {
x = from.x + (to.x - from.x) * s;
y = from.y + (to.y - from.y) * s;
return this;
}
public inline function equals(v: Vec2): Bool {
return x == v.x && y == v.y;
}
public inline function length(): FastFloat {
return Math.sqrt(x * x + y * y);
}
public inline function sub(v: Vec2): Vec2 {
x -= v.x;
y -= v.y;
return this;
}
public inline function exp(v: Vec2): Vec2 {
x = Math.exp(v.x);
y = Math.exp(v.y);
return this;
}
public static inline function distance(v1: Vec2, v2: Vec2): FastFloat {
return distancef(v1.x, v1.y, v2.x, v2.y);
}
public static inline function distancef(v1x: FastFloat, v1y: FastFloat, v2x: FastFloat, v2y: FastFloat): FastFloat {
var vx = v1x - v2x;
var vy = v1y - v2y;
return Math.sqrt(vx * vx + vy * vy);
}
public inline function distanceTo(p: Vec2): FastFloat {
return Math.sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y));
}
public inline function clamp(min: FastFloat, max: FastFloat): Vec2 {
var l = length();
if (l < min) normalize().mult(min);
else if (l > max) normalize().mult(max);
return this;
}
public static inline function xAxis(): Vec2 {
return new Vec2(1.0, 0.0);
}
public static inline function yAxis(): Vec2 {
return new Vec2(0.0, 1.0);
}
public function toString(): String {
return "(" + this.x + ", " + this.y + ")";
}
}

View File

@ -0,0 +1,181 @@
package iron.math;
import kha.FastFloat;
class Vec3 {
public var x: FastFloat;
public var y: FastFloat;
public var z: FastFloat;
public inline function new(x: FastFloat = 0.0, y: FastFloat = 0.0, z: FastFloat = 0.0) {
this.x = x;
this.y = y;
this.z = z;
}
public inline function cross(v: Vec3): Vec3 {
var ax = x; var ay = y; var az = z;
var vx = v.x; var vy = v.y; var vz = v.z;
x = ay * vz - az * vy;
y = az * vx - ax * vz;
z = ax * vy - ay * vx;
return this;
}
public inline function crossvecs(a: Vec3, b: Vec3): Vec3 {
var ax = a.x; var ay = a.y; var az = a.z;
var bx = b.x; var by = b.y; var bz = b.z;
x = ay * bz - az * by;
y = az * bx - ax * bz;
z = ax * by - ay * bx;
return this;
}
public inline function set(x: FastFloat, y: FastFloat, z: FastFloat): Vec3{
this.x = x;
this.y = y;
this.z = z;
return this;
}
public inline function add(v: Vec3): Vec3 {
x += v.x;
y += v.y;
z += v.z;
return this;
}
public inline function addf(x: FastFloat, y: FastFloat, z: FastFloat): Vec3 {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public inline function addvecs(a: Vec3, b: Vec3): Vec3 {
x = a.x + b.x;
y = a.y + b.y;
z = a.z + b.z;
return this;
}
public inline function subvecs(a: Vec3, b: Vec3): Vec3 {
x = a.x - b.x;
y = a.y - b.y;
z = a.z - b.z;
return this;
}
public inline function normalize(): Vec3 {
var n = length();
if (n > 0.0) {
var invN = 1.0 / n;
this.x *= invN; this.y *= invN; this.z *= invN;
}
return this;
}
public inline function mult(f: FastFloat): Vec3 {
x *= f;
y *= f;
z *= f;
return this;
}
public inline function dot(v: Vec3): FastFloat {
return x * v.x + y * v.y + z * v.z;
}
public inline function setFrom(v: Vec3): Vec3 {
x = v.x;
y = v.y;
z = v.z;
return this;
}
public inline function clone(): Vec3 {
return new Vec3(x, y, z);
}
public inline function lerp(from: Vec3, to: Vec3, s: FastFloat): Vec3 {
x = from.x + (to.x - from.x) * s;
y = from.y + (to.y - from.y) * s;
z = from.z + (to.z - from.z) * s;
return this;
}
public inline function applyproj(m: Mat4): Vec3 {
var x = this.x; var y = this.y; var z = this.z;
var d = 1.0 / (m._03 * x + m._13 * y + m._23 * z + m._33); // Perspective divide
this.x = (m._00 * x + m._10 * y + m._20 * z + m._30) * d;
this.y = (m._01 * x + m._11 * y + m._21 * z + m._31) * d;
this.z = (m._02 * x + m._12 * y + m._22 * z + m._32) * d;
return this;
}
public inline function applymat(m: Mat4): Vec3 {
var x = this.x; var y = this.y; var z = this.z;
this.x = m._00 * x + m._10 * y + m._20 * z + m._30;
this.y = m._01 * x + m._11 * y + m._21 * z + m._31;
this.z = m._02 * x + m._12 * y + m._22 * z + m._32;
return this;
}
public inline function equals(v: Vec3): Bool {
return x == v.x && y == v.y && z == v.z;
}
public inline function length(): FastFloat {
return Math.sqrt(x * x + y * y + z * z);
}
public inline function sub(v: Vec3): Vec3 {
x -= v.x; y -= v.y; z -= v.z;
return this;
}
public inline function exp(v: Vec3): Vec3 {
x = Math.exp(v.x);
y = Math.exp(v.y);
z = Math.exp(v.z);
return this;
}
public static inline function distance(v1: Vec3, v2: Vec3): FastFloat {
return distancef(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
}
public static inline function distancef(v1x: FastFloat, v1y: FastFloat, v1z: FastFloat, v2x: FastFloat, v2y: FastFloat, v2z: FastFloat): FastFloat {
var vx = v1x - v2x;
var vy = v1y - v2y;
var vz = v1z - v2z;
return Math.sqrt(vx * vx + vy * vy + vz * vz);
}
public inline function distanceTo(p: Vec3): FastFloat {
return Math.sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y) + (p.z - z) * (p.z - z));
}
public inline function clamp(min: FastFloat, max: FastFloat): Vec3 {
var l = length();
if (l < min) normalize().mult(min);
else if (l > max) normalize().mult(max);
return this;
}
public static inline function xAxis(): Vec3 {
return new Vec3(1.0, 0.0, 0.0);
}
public static inline function yAxis(): Vec3 {
return new Vec3(0.0, 1.0, 0.0);
}
public static inline function zAxis(): Vec3 {
return new Vec3(0.0, 0.0, 1.0);
}
public function toString(): String {
return "(" + this.x + ", " + this.y + ", " + this.z + ")";
}
}

View File

@ -0,0 +1,226 @@
package iron.math;
import kha.FastFloat;
class Vec4 {
public var x: FastFloat;
public var y: FastFloat;
public var z: FastFloat;
public var w: FastFloat;
public inline function new(x: FastFloat = 0.0, y: FastFloat = 0.0, z: FastFloat = 0.0, w: FastFloat = 1.0) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
public inline function cross(v: Vec4): Vec4 {
var ax = x; var ay = y; var az = z;
var vx = v.x; var vy = v.y; var vz = v.z;
x = ay * vz - az * vy;
y = az * vx - ax * vz;
z = ax * vy - ay * vx;
return this;
}
public inline function crossvecs(a: Vec4, b: Vec4): Vec4 {
var ax = a.x; var ay = a.y; var az = a.z;
var bx = b.x; var by = b.y; var bz = b.z;
x = ay * bz - az * by;
y = az * bx - ax * bz;
z = ax * by - ay * bx;
return this;
}
public inline function set(x: FastFloat, y: FastFloat, z: FastFloat, w: FastFloat = 1.0): Vec4{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
}
public inline function add(v: Vec4): Vec4 {
x += v.x;
y += v.y;
z += v.z;
return this;
}
public inline function addf(x: FastFloat, y: FastFloat, z: FastFloat): Vec4 {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public inline function addvecs(a: Vec4, b: Vec4): Vec4 {
x = a.x + b.x;
y = a.y + b.y;
z = a.z + b.z;
return this;
}
public inline function subvecs(a: Vec4, b: Vec4): Vec4 {
x = a.x - b.x;
y = a.y - b.y;
z = a.z - b.z;
return this;
}
public inline function normalize(): Vec4 {
var n = length();
if (n > 0.0) {
var invN = 1.0 / n;
this.x *= invN;
this.y *= invN;
this.z *= invN;
}
return this;
}
public inline function mult(f: FastFloat): Vec4 {
x *= f;
y *= f;
z *= f;
return this;
}
public inline function dot(v: Vec4): FastFloat {
return x * v.x + y * v.y + z * v.z;
}
public inline function setFrom(v: Vec4): Vec4 {
x = v.x;
y = v.y;
z = v.z;
w = v.w;
return this;
}
public inline function clone(): Vec4 {
return new Vec4(x, y, z, w);
}
public inline function lerp(from: Vec4, to: Vec4, s: FastFloat): Vec4 {
x = from.x + (to.x - from.x) * s;
y = from.y + (to.y - from.y) * s;
z = from.z + (to.z - from.z) * s;
return this;
}
public inline function applyproj(m: Mat4): Vec4 {
var x = this.x; var y = this.y; var z = this.z;
var d = 1.0 / (m._03 * x + m._13 * y + m._23 * z + m._33); // Perspective divide
this.x = (m._00 * x + m._10 * y + m._20 * z + m._30) * d;
this.y = (m._01 * x + m._11 * y + m._21 * z + m._31) * d;
this.z = (m._02 * x + m._12 * y + m._22 * z + m._32) * d;
return this;
}
public inline function applymat(m: Mat4): Vec4 {
var x = this.x; var y = this.y; var z = this.z;
this.x = m._00 * x + m._10 * y + m._20 * z + m._30;
this.y = m._01 * x + m._11 * y + m._21 * z + m._31;
this.z = m._02 * x + m._12 * y + m._22 * z + m._32;
return this;
}
public inline function applymat4(m: Mat4): Vec4 {
var x = this.x; var y = this.y; var z = this.z; var w = this.w;
this.x = m._00 * x + m._10 * y + m._20 * z + m._30 * w;
this.y = m._01 * x + m._11 * y + m._21 * z + m._31 * w;
this.z = m._02 * x + m._12 * y + m._22 * z + m._32 * w;
this.w = m._03 * x + m._13 * y + m._23 * z + m._33 * w;
return this;
}
public inline function applyAxisAngle(axis: Vec4, angle: FastFloat): Vec4 {
var quat = new Quat();
quat.fromAxisAngle(axis, angle);
return applyQuat(quat);
}
public inline function applyQuat(q: Quat): Vec4 {
var ix = q.w * x + q.y * z - q.z * y;
var iy = q.w * y + q.z * x - q.x * z;
var iz = q.w * z + q.x * y - q.y * x;
var iw = -q.x * x - q.y * y - q.z * z;
x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;
y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;
z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;
return this;
}
public inline function equals(v: Vec4): Bool {
return x == v.x && y == v.y && z == v.z;
}
public inline function almostEquals(v: Vec4, prec: FastFloat): Bool {
return Math.abs(x - v.x) < prec && Math.abs(y - v.y) < prec && Math.abs(z - v.z) < prec;
}
public inline function length(): FastFloat {
return Math.sqrt(x * x + y * y + z * z);
}
public inline function sub(v: Vec4): Vec4 {
x -= v.x; y -= v.y; z -= v.z;
return this;
}
public inline function exp(v: Vec4): Vec4 {
x = Math.exp(v.x);
y = Math.exp(v.y);
z = Math.exp(v.z);
return this;
}
public static inline function distance(v1: Vec4, v2: Vec4): FastFloat {
return distancef(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
}
public static inline function distancef(v1x: FastFloat, v1y: FastFloat, v1z: FastFloat, v2x: FastFloat, v2y: FastFloat, v2z: FastFloat): FastFloat {
var vx = v1x - v2x;
var vy = v1y - v2y;
var vz = v1z - v2z;
return Math.sqrt(vx * vx + vy * vy + vz * vz);
}
public inline function distanceTo(p: Vec4): FastFloat {
return Math.sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y) + (p.z - z) * (p.z - z));
}
public inline function reflect(n: Vec4): Vec4 {
var d = 2 * this.dot(n);
x = x - d * n.x;
y = y - d * n.y;
z = z - d * n.z;
return this;
}
public inline function clamp(min: FastFloat, max: FastFloat): Vec4 {
var l = length();
if (l < min) normalize().mult(min);
else if (l > max) normalize().mult(max);
return this;
}
public static inline function xAxis(): Vec4 {
return new Vec4(1.0, 0.0, 0.0);
}
public static inline function yAxis(): Vec4 {
return new Vec4(0.0, 1.0, 0.0);
}
public static inline function zAxis(): Vec4 {
return new Vec4(0.0, 0.0, 1.0);
}
public function toString(): String {
return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")";
}
}