= -nxW) {
+ plane = PLANE_PX;
+ inside &= nxX * (nxX < 0 ? maxX : minX) + nxY * (nxY < 0 ? maxY : minY) + nxZ * (nxZ < 0 ? maxZ : minZ) >= -nxW;
+ if ((mask & PLANE_MASK_PX) == 0 || pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW) {
+ plane = PLANE_NY;
+ inside &= pxX * (pxX < 0 ? maxX : minX) + pxY * (pxY < 0 ? maxY : minY) + pxZ * (pxZ < 0 ? maxZ : minZ) >= -pxW;
+ if ((mask & PLANE_MASK_NY) == 0 || nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW) {
+ plane = PLANE_PY;
+ inside &= nyX * (nyX < 0 ? maxX : minX) + nyY * (nyY < 0 ? maxY : minY) + nyZ * (nyZ < 0 ? maxZ : minZ) >= -nyW;
+ if ((mask & PLANE_MASK_PY) == 0 || pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW) {
+ plane = PLANE_NZ;
+ inside &= pyX * (pyX < 0 ? maxX : minX) + pyY * (pyY < 0 ? maxY : minY) + pyZ * (pyZ < 0 ? maxZ : minZ) >= -pyW;
+ if ((mask & PLANE_MASK_NZ) == 0 || nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW) {
+ plane = PLANE_PZ;
+ inside &= nzX * (nzX < 0 ? maxX : minX) + nzY * (nzY < 0 ? maxY : minY) + nzZ * (nzZ < 0 ? maxZ : minZ) >= -nzW;
+ if ((mask & PLANE_MASK_PZ) == 0 || pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW) {
+ inside &= pzX * (pzX < 0 ? maxX : minX) + pzY * (pzY < 0 ? maxY : minY) + pzZ * (pzZ < 0 ? maxZ : minZ) >= -pzW;
+ return inside ? INSIDE : INTERSECT;
+ }
+ }
+ }
+ }
+ }
+ }
+ return plane;
+ }
+
+ /**
+ * Test whether the given line segment, defined by the end points a
and b
,
+ * is partly or completely within the frustum defined by this
frustum culler.
+ *
+ * @param a
+ * the line segment's first end point
+ * @param b
+ * the line segment's second end point
+ * @return true
if the given line segment is partly or completely inside the frustum;
+ * false
otherwise
+ */
+ public boolean testLineSegment(Vector3fc a, Vector3fc b) {
+ return testLineSegment(a.x(), a.y(), a.z(), b.x(), b.y(), b.z());
+ }
+
+ /**
+ * Test whether the given line segment, defined by the end points (aX, aY, aZ)
and (bX, bY, bZ)
,
+ * is partly or completely within the frustum defined by this
frustum culler.
+ *
+ * @param aX
+ * the x coordinate of the line segment's first end point
+ * @param aY
+ * the y coordinate of the line segment's first end point
+ * @param aZ
+ * the z coordinate of the line segment's first end point
+ * @param bX
+ * the x coordinate of the line segment's second end point
+ * @param bY
+ * the y coordinate of the line segment's second end point
+ * @param bZ
+ * the z coordinate of the line segment's second end point
+ * @return true
if the given line segment is partly or completely inside the frustum;
+ * false
otherwise
+ */
+ public boolean testLineSegment(float aX, float aY, float aZ, float bX, float bY, float bZ) {
+ float da, db;
+ da = Math.fma(nxX, aX, Math.fma(nxY, aY, Math.fma(nxZ, aZ, nxW)));
+ db = Math.fma(nxX, bX, Math.fma(nxY, bY, Math.fma(nxZ, bZ, nxW)));
+ if (da < 0.0f && db < 0.0f)
+ return false;
+ if (da * db < 0.0f) {
+ float p = Math.abs(da) / Math.abs(db - da);
+ float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
+ if (da < 0.0f) {
+ aX = dx; aY = dy; aZ = dz;
+ } else {
+ bX = dx; bY = dy; bZ = dz;
+ }
+ }
+ da = Math.fma(pxX, aX, Math.fma(pxY, aY, Math.fma(pxZ, aZ, pxW)));
+ db = Math.fma(pxX, bX, Math.fma(pxY, bY, Math.fma(pxZ, bZ, pxW)));
+ if (da < 0.0f && db < 0.0f)
+ return false;
+ if (da * db < 0.0f) {
+ float p = Math.abs(da) / Math.abs(db - da);
+ float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
+ if (da < 0.0f) {
+ aX = dx; aY = dy; aZ = dz;
+ } else {
+ bX = dx; bY = dy; bZ = dz;
+ }
+ }
+ da = Math.fma(nyX, aX, Math.fma(nyY, aY, Math.fma(nyZ, aZ, nyW)));
+ db = Math.fma(nyX, bX, Math.fma(nyY, bY, Math.fma(nyZ, bZ, nyW)));
+ if (da < 0.0f && db < 0.0f)
+ return false;
+ if (da * db < 0.0f) {
+ float p = Math.abs(da) / Math.abs(db - da);
+ float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
+ if (da < 0.0f) {
+ aX = dx; aY = dy; aZ = dz;
+ } else {
+ bX = dx; bY = dy; bZ = dz;
+ }
+ }
+ da = Math.fma(pyX, aX, Math.fma(pyY, aY, Math.fma(pyZ, aZ, pyW)));
+ db = Math.fma(pyX, bX, Math.fma(pyY, bY, Math.fma(pyZ, bZ, pyW)));
+ if (da < 0.0f && db < 0.0f)
+ return false;
+ if (da * db < 0.0f) {
+ float p = Math.abs(da) / Math.abs(db - da);
+ float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
+ if (da < 0.0f) {
+ aX = dx; aY = dy; aZ = dz;
+ } else {
+ bX = dx; bY = dy; bZ = dz;
+ }
+ }
+ da = Math.fma(nzX, aX, Math.fma(nzY, aY, Math.fma(nzZ, aZ, nzW)));
+ db = Math.fma(nzX, bX, Math.fma(nzY, bY, Math.fma(nzZ, bZ, nzW)));
+ if (da < 0.0f && db < 0.0f)
+ return false;
+ if (da * db < 0.0f) {
+ float p = Math.abs(da) / Math.abs(db - da);
+ float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
+ if (da < 0.0f) {
+ aX = dx; aY = dy; aZ = dz;
+ } else {
+ bX = dx; bY = dy; bZ = dz;
+ }
+ }
+ da = Math.fma(pzX, aX, Math.fma(pzY, aY, Math.fma(pzZ, aZ, pzW)));
+ db = Math.fma(pzX, bX, Math.fma(pzY, bY, Math.fma(pzZ, bZ, pzW)));
+ return da >= 0.0f || db >= 0.0f;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/FrustumRayBuilder.java b/src/main/java/com/jozufozu/flywheel/repack/joml/FrustumRayBuilder.java
new file mode 100644
index 000000000..5520ca304
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/FrustumRayBuilder.java
@@ -0,0 +1,154 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Provides methods to compute rays through an arbitrary perspective transformation defined by a {@link Matrix4fc}.
+ *
+ * This can be used to compute the eye-rays in simple software-based raycasting/raytracing.
+ *
+ * To obtain the origin of the rays call {@link #origin(Vector3f)}.
+ * Then to compute the directions of subsequent rays use {@link #dir(float, float, Vector3f)}.
+ *
+ * @author Kai Burjack
+ */
+public class FrustumRayBuilder {
+
+ private float nxnyX, nxnyY, nxnyZ;
+ private float pxnyX, pxnyY, pxnyZ;
+ private float pxpyX, pxpyY, pxpyZ;
+ private float nxpyX, nxpyY, nxpyZ;
+ private float cx, cy, cz;
+
+ /**
+ * Create a new {@link FrustumRayBuilder} with an undefined frustum.
+ *
+ * Before obtaining ray directions, make sure to define the frustum using {@link #set(Matrix4fc)}.
+ */
+ public FrustumRayBuilder() {
+ }
+
+ /**
+ * Create a new {@link FrustumRayBuilder} from the given {@link Matrix4fc matrix} by extracing the matrix's frustum.
+ *
+ * @param m
+ * the {@link Matrix4fc} to create the frustum from
+ */
+ public FrustumRayBuilder(Matrix4fc m) {
+ set(m);
+ }
+
+ /**
+ * Update the stored frustum corner rays and origin of this
{@link FrustumRayBuilder} with the given {@link Matrix4fc matrix}.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * Reference: http://geomalgorithms.com
+ *
+ * @param m
+ * the {@link Matrix4fc matrix} to update the frustum corner rays and origin with
+ * @return this
+ */
+ public FrustumRayBuilder set(Matrix4fc m) {
+ float nxX = m.m03() + m.m00(), nxY = m.m13() + m.m10(), nxZ = m.m23() + m.m20(), d1 = m.m33() + m.m30();
+ float pxX = m.m03() - m.m00(), pxY = m.m13() - m.m10(), pxZ = m.m23() - m.m20(), d2 = m.m33() - m.m30();
+ float nyX = m.m03() + m.m01(), nyY = m.m13() + m.m11(), nyZ = m.m23() + m.m21();
+ float pyX = m.m03() - m.m01(), pyY = m.m13() - m.m11(), pyZ = m.m23() - m.m21(), d3 = m.m33() - m.m31();
+ // bottom left
+ nxnyX = nyY * nxZ - nyZ * nxY;
+ nxnyY = nyZ * nxX - nyX * nxZ;
+ nxnyZ = nyX * nxY - nyY * nxX;
+ // bottom right
+ pxnyX = pxY * nyZ - pxZ * nyY;
+ pxnyY = pxZ * nyX - pxX * nyZ;
+ pxnyZ = pxX * nyY - pxY * nyX;
+ // top left
+ nxpyX = nxY * pyZ - nxZ * pyY;
+ nxpyY = nxZ * pyX - nxX * pyZ;
+ nxpyZ = nxX * pyY - nxY * pyX;
+ // top right
+ pxpyX = pyY * pxZ - pyZ * pxY;
+ pxpyY = pyZ * pxX - pyX * pxZ;
+ pxpyZ = pyX * pxY - pyY * pxX;
+ // compute origin
+ float pxnxX, pxnxY, pxnxZ;
+ pxnxX = pxY * nxZ - pxZ * nxY;
+ pxnxY = pxZ * nxX - pxX * nxZ;
+ pxnxZ = pxX * nxY - pxY * nxX;
+ float invDot = 1.0f / (nxX * pxpyX + nxY * pxpyY + nxZ * pxpyZ);
+ cx = (-pxpyX * d1 - nxpyX * d2 - pxnxX * d3) * invDot;
+ cy = (-pxpyY * d1 - nxpyY * d2 - pxnxY * d3) * invDot;
+ cz = (-pxpyZ * d1 - nxpyZ * d2 - pxnxZ * d3) * invDot;
+ return this;
+ }
+
+ /**
+ * Store the eye/origin of the perspective frustum in the given origin
.
+ *
+ * @param origin
+ * will hold the perspective origin
+ * @return the origin
vector
+ */
+ public Vector3fc origin(Vector3f origin) {
+ origin.x = cx;
+ origin.y = cy;
+ origin.z = cz;
+ return origin;
+ }
+
+ /**
+ * Obtain the normalized direction of a ray starting at the center of the coordinate system and going
+ * through the near frustum plane.
+ *
+ * The parameters x
and y
are used to interpolate the generated ray direction
+ * from the bottom-left to the top-right frustum corners.
+ *
+ * @param x
+ * the interpolation factor along the left-to-right frustum planes, within [0..1]
+ * @param y
+ * the interpolation factor along the bottom-to-top frustum planes, within [0..1]
+ * @param dir
+ * will hold the normalized ray direction
+ * @return the dir
vector
+ */
+ public Vector3fc dir(float x, float y, Vector3f dir) {
+ float y1x = nxnyX + (nxpyX - nxnyX) * y;
+ float y1y = nxnyY + (nxpyY - nxnyY) * y;
+ float y1z = nxnyZ + (nxpyZ - nxnyZ) * y;
+ float y2x = pxnyX + (pxpyX - pxnyX) * y;
+ float y2y = pxnyY + (pxpyY - pxnyY) * y;
+ float y2z = pxnyZ + (pxpyZ - pxnyZ) * y;
+ float dx = y1x + (y2x - y1x) * x;
+ float dy = y1y + (y2y - y1y) * x;
+ float dz = y1z + (y2z - y1z) * x;
+ // normalize the vector
+ float invLen = Math.invsqrt(dx * dx + dy * dy + dz * dz);
+ dir.x = dx * invLen;
+ dir.y = dy * invLen;
+ dir.z = dz * invLen;
+ return dir;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/GeometryUtils.java b/src/main/java/com/jozufozu/flywheel/repack/joml/GeometryUtils.java
new file mode 100644
index 000000000..88a2c1c11
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/GeometryUtils.java
@@ -0,0 +1,247 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Useful geometry methods.
+ *
+ * @author Kai Burjack
+ * @author Richard Greenlees
+ */
+public class GeometryUtils {
+
+ /**
+ * Compute two arbitrary vectors perpendicular to the given normalized vector (x, y, z)
, and store them in dest1
and dest2
,
+ * respectively.
+ *
+ * The computed vectors will themselves be perpendicular to each another and normalized. So the tree vectors (x, y, z)
, dest1
and
+ * dest2
form an orthonormal basis.
+ *
+ * @param x
+ * the x coordinate of the normalized input vector
+ * @param y
+ * the y coordinate of the normalized input vector
+ * @param z
+ * the z coordinate of the normalized input vector
+ * @param dest1
+ * will hold the first perpendicular vector
+ * @param dest2
+ * will hold the second perpendicular vector
+ */
+ public static void perpendicular(float x, float y, float z, Vector3f dest1, Vector3f dest2) {
+ float magX = z * z + y * y;
+ float magY = z * z + x * x;
+ float magZ = y * y + x * x;
+ float mag;
+ if (magX > magY && magX > magZ) {
+ dest1.x = 0;
+ dest1.y = z;
+ dest1.z = -y;
+ mag = magX;
+ } else if (magY > magZ) {
+ dest1.x = -z;
+ dest1.y = 0;
+ dest1.z = x;
+ mag = magY;
+ } else {
+ dest1.x = y;
+ dest1.y = -x;
+ dest1.z = 0;
+ mag = magZ;
+ }
+ float len = Math.invsqrt(mag);
+ dest1.x *= len;
+ dest1.y *= len;
+ dest1.z *= len;
+ dest2.x = y * dest1.z - z * dest1.y;
+ dest2.y = z * dest1.x - x * dest1.z;
+ dest2.z = x * dest1.y - y * dest1.x;
+ }
+
+ /**
+ * Compute two arbitrary vectors perpendicular to the given normalized vector v
, and store them in dest1
and dest2
,
+ * respectively.
+ *
+ * The computed vectors will themselves be perpendicular to each another and normalized. So the tree vectors v
, dest1
and
+ * dest2
form an orthonormal basis.
+ *
+ * @param v
+ * the {@link Vector3f#normalize() normalized} input vector
+ * @param dest1
+ * will hold the first perpendicular vector
+ * @param dest2
+ * will hold the second perpendicular vector
+ */
+ public static void perpendicular(Vector3fc v, Vector3f dest1, Vector3f dest2) {
+ perpendicular(v.x(), v.y(), v.z(), dest1, dest2);
+ }
+
+ /**
+ * Calculate the normal of a surface defined by points v1
, v2
and v3
and store it in dest
.
+ *
+ * @param v0
+ * the first position
+ * @param v1
+ * the second position
+ * @param v2
+ * the third position
+ * @param dest
+ * will hold the result
+ */
+ public static void normal(Vector3fc v0, Vector3fc v1, Vector3fc v2, Vector3f dest) {
+ normal(v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), dest);
+ }
+
+ /**
+ * Calculate the normal of a surface defined by points (v1X, v1Y, v1Z)
, (v2X, v2Y, v2Z)
and (v3X, v3Y, v3Z)
+ * and store it in dest
.
+ *
+ * @param v0X
+ * the x coordinate of the first position
+ * @param v0Y
+ * the y coordinate of the first position
+ * @param v0Z
+ * the z coordinate of the first position
+ * @param v1X
+ * the x coordinate of the second position
+ * @param v1Y
+ * the y coordinate of the second position
+ * @param v1Z
+ * the z coordinate of the second position
+ * @param v2X
+ * the x coordinate of the third position
+ * @param v2Y
+ * the y coordinate of the third position
+ * @param v2Z
+ * the z coordinate of the third position
+ * @param dest
+ * will hold the result
+ */
+ public static void normal(float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z, Vector3f dest) {
+ dest.x = ((v1Y - v0Y) * (v2Z - v0Z)) - ((v1Z - v0Z) * (v2Y - v0Y));
+ dest.y = ((v1Z - v0Z) * (v2X - v0X)) - ((v1X - v0X) * (v2Z - v0Z));
+ dest.z = ((v1X - v0X) * (v2Y - v0Y)) - ((v1Y - v0Y) * (v2X - v0X));
+ dest.normalize();
+ }
+
+ /**
+ * Calculate the surface tangent for the three supplied vertices and UV coordinates and store the result in dest
.
+ *
+ * @param v1
+ * XYZ of first vertex
+ * @param uv1
+ * UV of first vertex
+ * @param v2
+ * XYZ of second vertex
+ * @param uv2
+ * UV of second vertex
+ * @param v3
+ * XYZ of third vertex
+ * @param uv3
+ * UV of third vertex
+ * @param dest
+ * the tangent will be stored here
+ */
+ public static void tangent(Vector3fc v1, Vector2fc uv1, Vector3fc v2, Vector2fc uv2, Vector3fc v3, Vector2fc uv3, Vector3f dest) {
+ float DeltaV1 = uv2.y() - uv1.y();
+ float DeltaV2 = uv3.y() - uv1.y();
+
+ float f = 1.0f / ((uv2.x() - uv1.x()) * DeltaV2 - (uv3.x() - uv1.x()) * DeltaV1);
+
+ dest.x = f * (DeltaV2 * (v2.x() - v1.x()) - DeltaV1 * (v3.x() - v1.x()));
+ dest.y = f * (DeltaV2 * (v2.y() - v1.y()) - DeltaV1 * (v3.y() - v1.y()));
+ dest.z = f * (DeltaV2 * (v2.z() - v1.z()) - DeltaV1 * (v3.z() - v1.z()));
+ dest.normalize();
+ }
+
+ /**
+ * Calculate the surface bitangent for the three supplied vertices and UV coordinates and store the result in dest
.
+ *
+ * @param v1
+ * XYZ of first vertex
+ * @param uv1
+ * UV of first vertex
+ * @param v2
+ * XYZ of second vertex
+ * @param uv2
+ * UV of second vertex
+ * @param v3
+ * XYZ of third vertex
+ * @param uv3
+ * UV of third vertex
+ * @param dest
+ * the binormal will be stored here
+ */
+ public static void bitangent(Vector3fc v1, Vector2fc uv1, Vector3fc v2, Vector2fc uv2, Vector3fc v3, Vector2fc uv3, Vector3f dest) {
+ float DeltaU1 = uv2.x() - uv1.x();
+ float DeltaU2 = uv3.x() - uv1.x();
+
+ float f = 1.0f / (DeltaU1 * (uv3.y() - uv1.y()) - DeltaU2 * (uv2.y() - uv1.y()));
+
+ dest.x = f * (-DeltaU2 * (v2.x() - v1.x()) + DeltaU1 * (v3.x() - v1.x()));
+ dest.y = f * (-DeltaU2 * (v2.y() - v1.y()) + DeltaU1 * (v3.y() - v1.y()));
+ dest.z = f * (-DeltaU2 * (v2.z() - v1.z()) + DeltaU1 * (v3.z() - v1.z()));
+ dest.normalize();
+ }
+
+ /**
+ * Calculate the surface tangent and bitangent for the three supplied vertices and UV coordinates and store the result in dest
.
+ *
+ * @param v1
+ * XYZ of first vertex
+ * @param uv1
+ * UV of first vertex
+ * @param v2
+ * XYZ of second vertex
+ * @param uv2
+ * UV of second vertex
+ * @param v3
+ * XYZ of third vertex
+ * @param uv3
+ * UV of third vertex
+ * @param destTangent
+ * the tangent will be stored here
+ * @param destBitangent
+ * the bitangent will be stored here
+ */
+ public static void tangentBitangent(Vector3fc v1, Vector2fc uv1, Vector3fc v2, Vector2fc uv2, Vector3fc v3, Vector2fc uv3, Vector3f destTangent, Vector3f destBitangent) {
+ float DeltaV1 = uv2.y() - uv1.y();
+ float DeltaV2 = uv3.y() - uv1.y();
+ float DeltaU1 = uv2.x() - uv1.x();
+ float DeltaU2 = uv3.x() - uv1.x();
+
+ float f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1);
+
+ destTangent.x = f * (DeltaV2 * (v2.x() - v1.x()) - DeltaV1 * (v3.x() - v1.x()));
+ destTangent.y = f * (DeltaV2 * (v2.y() - v1.y()) - DeltaV1 * (v3.y() - v1.y()));
+ destTangent.z = f * (DeltaV2 * (v2.z() - v1.z()) - DeltaV1 * (v3.z() - v1.z()));
+ destTangent.normalize();
+
+ destBitangent.x = f * (-DeltaU2 * (v2.x() - v1.x()) + DeltaU1 * (v3.x() - v1.x()));
+ destBitangent.y = f * (-DeltaU2 * (v2.y() - v1.y()) + DeltaU1 * (v3.y() - v1.y()));
+ destBitangent.z = f * (-DeltaU2 * (v2.z() - v1.z()) + DeltaU1 * (v3.z() - v1.z()));
+ destBitangent.normalize();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Interpolationd.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Interpolationd.java
new file mode 100644
index 000000000..bbe11ef61
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Interpolationd.java
@@ -0,0 +1,337 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Contains various interpolation functions.
+ *
+ * @author Kai Burjack
+ */
+public class Interpolationd {
+
+ /**
+ * Bilinearly interpolate the single scalar value f over the given triangle.
+ *
+ * Reference: https://en.wikipedia.org/
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0
+ * the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1
+ * the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2
+ * the value of f at the third vertex
+ * @param x
+ * the x coordinate of the point to interpolate f at
+ * @param y
+ * the y coordinate of the point to interpolate f at
+ * @return the interpolated value of f
+ */
+ public static double interpolateTriangle(
+ double v0X, double v0Y, double f0,
+ double v1X, double v1Y, double f1,
+ double v2X, double v2Y, double f2,
+ double x, double y) {
+ double v12Y = v1Y - v2Y;
+ double v21X = v2X - v1X;
+ double v02X = v0X - v2X;
+ double yv2Y = y - v2Y;
+ double xv2X = x - v2X;
+ double v02Y = v0Y - v2Y;
+ double invDen = 1.0 / (v12Y * v02X + v21X * v02Y);
+ double l1 = (v12Y * xv2X + v21X * yv2Y) * invDen;
+ double l2 = (v02X * yv2Y - v02Y * xv2X) * invDen;
+ return l1 * f0 + l2 * f1 + (1.0f - l1 - l2) * f2;
+ }
+
+ /**
+ * Bilinearly interpolate the two-dimensional vector f over the given triangle and store the result in dest
.
+ *
+ * Reference: https://en.wikipedia.org/
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param x
+ * the x coordinate of the point to interpolate f at
+ * @param y
+ * the y coordinate of the point to interpolate f at
+ * @param dest
+ * will hold the interpolation result
+ * @return dest
+ */
+ public static Vector2d interpolateTriangle(
+ double v0X, double v0Y, double f0X, double f0Y,
+ double v1X, double v1Y, double f1X, double f1Y,
+ double v2X, double v2Y, double f2X, double f2Y,
+ double x, double y, Vector2d dest) {
+ double v12Y = v1Y - v2Y;
+ double v21X = v2X - v1X;
+ double v02X = v0X - v2X;
+ double yv2Y = y - v2Y;
+ double xv2X = x - v2X;
+ double v02Y = v0Y - v2Y;
+ double invDen = 1.0 / (v12Y * v02X + v21X * v02Y);
+ double l1 = (v12Y * xv2X + v21X * yv2Y) * invDen;
+ double l2 = (v02X * yv2Y - v02Y * xv2X) * invDen;
+ double l3 = 1.0 - l1 - l2;
+ dest.x = l1 * f0X + l2 * f1X + l3 * f2X;
+ dest.y = l1 * f0Y + l2 * f1Y + l3 * f2Y;
+ return dest;
+ }
+
+ /**
+ * Compute the first-order derivative of a linear two-dimensional function f with respect to X
+ * and store the result in dest
.
+ *
+ * This method computes the constant rate of change for f given the three values of f
+ * at the specified three inputs (v0X, v0Y)
, (v1X, v1Y)
and (v2X, v2Y)
.
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Vector2d dFdxLinear(
+ double v0X, double v0Y, double f0X, double f0Y,
+ double v1X, double v1Y, double f1X, double f1Y,
+ double v2X, double v2Y, double f2X, double f2Y, Vector2d dest) {
+ double v12Y = v1Y - v2Y;
+ double v02Y = v0Y - v2Y;
+ double den = v12Y * (v0X - v2X) + (v2X - v1X) * v02Y;
+ double l3_1 = den - v12Y + v02Y;
+ double invDen = 1.0f / den;
+ dest.x = invDen * (v12Y * f0X - v02Y * f1X + l3_1 * f2X) - f2X;
+ dest.y = invDen * (v12Y * f0Y - v02Y * f1Y + l3_1 * f2Y) - f2Y;
+ return dest;
+ }
+
+ /**
+ * Compute the first-order derivative of a linear two-dimensional function f with respect to Y
+ * and store the result in dest
.
+ *
+ * This method computes the constant rate of change for f given the three values of f
+ * at the specified three inputs (v0X, v0Y)
, (v1X, v1Y)
and (v2X, v2Y)
.
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Vector2d dFdyLinear(
+ double v0X, double v0Y, double f0X, double f0Y,
+ double v1X, double v1Y, double f1X, double f1Y,
+ double v2X, double v2Y, double f2X, double f2Y,
+ Vector2d dest) {
+ double v21X = v2X - v1X;
+ double v02X = v0X - v2X;
+ double den = (v1Y - v2Y) * v02X + v21X * (v0Y - v2Y);
+ double l3_1 = den - v21X - v02X;
+ double invDen = 1.0f / den;
+ dest.x = invDen * (v21X * f0X + v02X * f1X + l3_1 * f2X) - f2X;
+ dest.y = invDen * (v21X * f0Y + v02X * f1Y + l3_1 * f2Y) - f2Y;
+ return dest;
+ }
+
+ /**
+ * Bilinearly interpolate the three-dimensional vector f over the given triangle and store the result in dest
.
+ *
+ * Reference: https://en.wikipedia.org/
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param f0Z
+ * the z component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param f1Z
+ * the z component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param f2Z
+ * the z component of the value of f at the third vertex
+ * @param x
+ * the x coordinate of the point to interpolate f at
+ * @param y
+ * the y coordinate of the point to interpolate f at
+ * @param dest
+ * will hold the interpolation result
+ * @return dest
+ */
+ public static Vector3d interpolateTriangle(
+ double v0X, double v0Y, double f0X, double f0Y, double f0Z,
+ double v1X, double v1Y, double f1X, double f1Y, double f1Z,
+ double v2X, double v2Y, double f2X, double f2Y, double f2Z,
+ double x, double y, Vector3d dest) {
+ // compute interpolation factors
+ Vector3d t = dest;
+ interpolationFactorsTriangle(v0X, v0Y, v1X, v1Y, v2X, v2Y, x, y, t);
+ // interpolate using these factors
+ return dest.set(t.x * f0X + t.y * f1X + t.z * f2X,
+ t.x * f0Y + t.y * f1Y + t.z * f2Y,
+ t.x * f0Z + t.y * f1Z + t.z * f2Z);
+ }
+
+ /**
+ * Compute the interpolation factors (t0, t1, t2)
in order to interpolate an arbitrary value over a given
+ * triangle at the given point (x, y)
.
+ *
+ * This method takes in the 2D vertex positions of the three vertices of a triangle and stores in dest
the
+ * factors (t0, t1, t2)
in the equation v' = v0 * t0 + v1 * t1 + v2 * t2
where (v0, v1, v2)
are
+ * arbitrary (scalar or vector) values associated with the respective vertices of the triangle. The computed value v'
+ * is the interpolated value at the given position (x, y)
.
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param x
+ * the x coordinate of the point to interpolate at
+ * @param y
+ * the y coordinate of the point to interpolate at
+ * @param dest
+ * will hold the interpolation factors (t0, t1, t2)
+ * @return dest
+ */
+ public static Vector3d interpolationFactorsTriangle(
+ double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y,
+ double x, double y, Vector3d dest) {
+ double v12Y = v1Y - v2Y;
+ double v21X = v2X - v1X;
+ double v02X = v0X - v2X;
+ double yv2Y = y - v2Y;
+ double xv2X = x - v2X;
+ double v02Y = v0Y - v2Y;
+ double invDen = 1.0 / (v12Y * v02X + v21X * v02Y);
+ dest.x = (v12Y * xv2X + v21X * yv2Y) * invDen;
+ dest.y = (v02X * yv2Y - v02Y * xv2X) * invDen;
+ dest.z = 1.0 - dest.x - dest.y;
+ return dest;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Interpolationf.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Interpolationf.java
new file mode 100644
index 000000000..a3e3f4233
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Interpolationf.java
@@ -0,0 +1,337 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Contains various interpolation functions.
+ *
+ * @author Kai Burjack
+ */
+public class Interpolationf {
+
+ /**
+ * Bilinearly interpolate the single scalar value f over the given triangle.
+ *
+ * Reference: https://en.wikipedia.org/
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0
+ * the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1
+ * the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2
+ * the value of f at the third vertex
+ * @param x
+ * the x coordinate of the point to interpolate f at
+ * @param y
+ * the y coordinate of the point to interpolate f at
+ * @return the interpolated value of f
+ */
+ public static float interpolateTriangle(
+ float v0X, float v0Y, float f0,
+ float v1X, float v1Y, float f1,
+ float v2X, float v2Y, float f2,
+ float x, float y) {
+ float v12Y = v1Y - v2Y;
+ float v21X = v2X - v1X;
+ float v02X = v0X - v2X;
+ float yv2Y = y - v2Y;
+ float xv2X = x - v2X;
+ float v02Y = v0Y - v2Y;
+ float invDen = 1.0f / (v12Y * v02X + v21X * v02Y);
+ float l1 = (v12Y * xv2X + v21X * yv2Y) * invDen;
+ float l2 = (v02X * yv2Y - v02Y * xv2X) * invDen;
+ return l1 * f0 + l2 * f1 + (1.0f - l1 - l2) * f2;
+ }
+
+ /**
+ * Bilinearly interpolate the two-dimensional vector f over the given triangle and store the result in dest
.
+ *
+ * Reference: https://en.wikipedia.org/
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param x
+ * the x coordinate of the point to interpolate f at
+ * @param y
+ * the y coordinate of the point to interpolate f at
+ * @param dest
+ * will hold the interpolation result
+ * @return dest
+ */
+ public static Vector2f interpolateTriangle(
+ float v0X, float v0Y, float f0X, float f0Y,
+ float v1X, float v1Y, float f1X, float f1Y,
+ float v2X, float v2Y, float f2X, float f2Y,
+ float x, float y, Vector2f dest) {
+ float v12Y = v1Y - v2Y;
+ float v21X = v2X - v1X;
+ float v02X = v0X - v2X;
+ float yv2Y = y - v2Y;
+ float xv2X = x - v2X;
+ float v02Y = v0Y - v2Y;
+ float invDen = 1.0f / (v12Y * v02X + v21X * v02Y);
+ float l1 = (v12Y * xv2X + v21X * yv2Y) * invDen;
+ float l2 = (v02X * yv2Y - v02Y * xv2X) * invDen;
+ float l3 = 1.0f - l1 - l2;
+ dest.x = l1 * f0X + l2 * f1X + l3 * f2X;
+ dest.y = l1 * f0Y + l2 * f1Y + l3 * f2Y;
+ return dest;
+ }
+
+ /**
+ * Compute the first-order derivative of a linear two-dimensional function f with respect to X
+ * and store the result in dest
.
+ *
+ * This method computes the constant rate of change for f given the three values of f
+ * at the specified three inputs (v0X, v0Y)
, (v1X, v1Y)
and (v2X, v2Y)
.
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Vector2f dFdxLinear(
+ float v0X, float v0Y, float f0X, float f0Y,
+ float v1X, float v1Y, float f1X, float f1Y,
+ float v2X, float v2Y, float f2X, float f2Y, Vector2f dest) {
+ float v12Y = v1Y - v2Y;
+ float v02Y = v0Y - v2Y;
+ float den = v12Y * (v0X - v2X) + (v2X - v1X) * v02Y;
+ float l3_1 = den - v12Y + v02Y;
+ float invDen = 1.0f / den;
+ dest.x = invDen * (v12Y * f0X - v02Y * f1X + l3_1 * f2X) - f2X;
+ dest.y = invDen * (v12Y * f0Y - v02Y * f1Y + l3_1 * f2Y) - f2Y;
+ return dest;
+ }
+
+ /**
+ * Compute the first-order derivative of a linear two-dimensional function f with respect to Y
+ * and store the result in dest
.
+ *
+ * This method computes the constant rate of change for f given the three values of f
+ * at the specified three inputs (v0X, v0Y)
, (v1X, v1Y)
and (v2X, v2Y)
.
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Vector2f dFdyLinear(
+ float v0X, float v0Y, float f0X, float f0Y,
+ float v1X, float v1Y, float f1X, float f1Y,
+ float v2X, float v2Y, float f2X, float f2Y,
+ Vector2f dest) {
+ float v21X = v2X - v1X;
+ float v02X = v0X - v2X;
+ float den = (v1Y - v2Y) * v02X + v21X * (v0Y - v2Y);
+ float l3_1 = den - v21X - v02X;
+ float invDen = 1.0f / den;
+ dest.x = invDen * (v21X * f0X + v02X * f1X + l3_1 * f2X) - f2X;
+ dest.y = invDen * (v21X * f0Y + v02X * f1Y + l3_1 * f2Y) - f2Y;
+ return dest;
+ }
+
+ /**
+ * Bilinearly interpolate the three-dimensional vector f over the given triangle and store the result in dest
.
+ *
+ * Reference: https://en.wikipedia.org/
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param f0X
+ * the x component of the value of f at the first vertex
+ * @param f0Y
+ * the y component of the value of f at the first vertex
+ * @param f0Z
+ * the z component of the value of f at the first vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param f1X
+ * the x component of the value of f at the second vertex
+ * @param f1Y
+ * the y component of the value of f at the second vertex
+ * @param f1Z
+ * the z component of the value of f at the second vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param f2X
+ * the x component of the value of f at the third vertex
+ * @param f2Y
+ * the y component of the value of f at the third vertex
+ * @param f2Z
+ * the z component of the value of f at the third vertex
+ * @param x
+ * the x coordinate of the point to interpolate f at
+ * @param y
+ * the y coordinate of the point to interpolate f at
+ * @param dest
+ * will hold the interpolation result
+ * @return dest
+ */
+ public static Vector3f interpolateTriangle(
+ float v0X, float v0Y, float f0X, float f0Y, float f0Z,
+ float v1X, float v1Y, float f1X, float f1Y, float f1Z,
+ float v2X, float v2Y, float f2X, float f2Y, float f2Z,
+ float x, float y, Vector3f dest) {
+ // compute interpolation factors
+ Vector3f t = dest;
+ interpolationFactorsTriangle(v0X, v0Y, v1X, v1Y, v2X, v2Y, x, y, t);
+ // interpolate using these factors
+ return dest.set(t.x * f0X + t.y * f1X + t.z * f2X,
+ t.x * f0Y + t.y * f1Y + t.z * f2Y,
+ t.x * f0Z + t.y * f1Z + t.z * f2Z);
+ }
+
+ /**
+ * Compute the interpolation factors (t0, t1, t2)
in order to interpolate an arbitrary value over a given
+ * triangle at the given point (x, y)
.
+ *
+ * This method takes in the 2D vertex positions of the three vertices of a triangle and stores in dest
the
+ * factors (t0, t1, t2)
in the equation v' = v0 * t0 + v1 * t1 + v2 * t2
where (v0, v1, v2)
are
+ * arbitrary (scalar or vector) values associated with the respective vertices of the triangle. The computed value v'
+ * is the interpolated value at the given position (x, y)
.
+ *
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param x
+ * the x coordinate of the point to interpolate at
+ * @param y
+ * the y coordinate of the point to interpolate at
+ * @param dest
+ * will hold the interpolation factors (t0, t1, t2)
+ * @return dest
+ */
+ public static Vector3f interpolationFactorsTriangle(
+ float v0X, float v0Y, float v1X, float v1Y, float v2X, float v2Y,
+ float x, float y, Vector3f dest) {
+ float v12Y = v1Y - v2Y;
+ float v21X = v2X - v1X;
+ float v02X = v0X - v2X;
+ float yv2Y = y - v2Y;
+ float xv2X = x - v2X;
+ float v02Y = v0Y - v2Y;
+ float invDen = 1.0f / (v12Y * v02X + v21X * v02Y);
+ dest.x = (v12Y * xv2X + v21X * yv2Y) * invDen;
+ dest.y = (v02X * yv2Y - v02Y * xv2X) * invDen;
+ dest.z = 1.0f - dest.x - dest.y;
+ return dest;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Intersectiond.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Intersectiond.java
new file mode 100644
index 000000000..16edb1abb
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Intersectiond.java
@@ -0,0 +1,4789 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Contains intersection and distance tests for some 2D and 3D geometric primitives.
+ *
+ * @author Kai Burjack
+ */
+public class Intersectiond {
+
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point is the first vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_VERTEX_0 = 1;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point is the second vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_VERTEX_1 = 2;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point is the third vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_VERTEX_2 = 3;
+
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the edge between the first and second vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_EDGE_01 = 4;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the edge between the second and third vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_EDGE_12 = 5;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the edge between the third and first vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_EDGE_20 = 6;
+
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)},
+ * {@link #findClosestPointOnTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3d)},
+ * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #findClosestPointOnTriangle(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the face of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_FACE = 7;
+
+ /**
+ * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectRayAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the minimum x coordinate.
+ */
+ public static final int AAR_SIDE_MINX = 0;
+ /**
+ * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectRayAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the minimum y coordinate.
+ */
+ public static final int AAR_SIDE_MINY = 1;
+ /**
+ * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectRayAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the maximum x coordinate.
+ */
+ public static final int AAR_SIDE_MAXX = 2;
+ /**
+ * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectRayAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the maximum y coordinate.
+ */
+ public static final int AAR_SIDE_MAXY = 3;
+
+ /**
+ * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)} to indicate that the line segment does not intersect the axis-aligned box;
+ * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} to indicate that the line segment does not intersect the axis-aligned rectangle.
+ */
+ public static final int OUTSIDE = -1;
+ /**
+ * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)} to indicate that one end point of the line segment lies inside of the axis-aligned box;
+ * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} to indicate that one end point of the line segment lies inside of the axis-aligned rectangle.
+ */
+ public static final int ONE_INTERSECTION = 1;
+ /**
+ * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)} to indicate that the line segment intersects two sides of the axis-aligned box
+ * or lies on an edge or a side of the box;
+ * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} to indicate that the line segment intersects two edges of the axis-aligned rectangle
+ * or lies on an edge of the rectangle.
+ */
+ public static final int TWO_INTERSECTION = 2;
+ /**
+ * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)} to indicate that the line segment lies completely inside of the axis-aligned box;
+ * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and
+ * {@link #intersectLineSegmentAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)} to indicate that the line segment lies completely inside of the axis-aligned rectangle.
+ */
+ public static final int INSIDE = 3;
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the sphere with center
+ * (centerX, centerY, centerZ)
and radius
.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radius
+ * the radius of the sphere
+ * @return true
iff the plane intersects the sphere; false
otherwise
+ */
+ public static boolean testPlaneSphere(
+ double a, double b, double c, double d,
+ double centerX, double centerY, double centerZ, double radius) {
+ double denom = Math.sqrt(a * a + b * b + c * c);
+ double dist = (a * centerX + b * centerY + c * centerZ + d) / denom;
+ return -radius <= dist && dist <= radius;
+ }
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the sphere with center
+ * (centerX, centerY, centerZ)
and radius
, and store the center of the circle of
+ * intersection in the (x, y, z)
components of the supplied vector and the radius of that circle in the w component.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radius
+ * the radius of the sphere
+ * @param intersectionCenterAndRadius
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff the plane intersects the sphere; false
otherwise
+ */
+ public static boolean intersectPlaneSphere(
+ double a, double b, double c, double d,
+ double centerX, double centerY, double centerZ, double radius,
+ Vector4d intersectionCenterAndRadius) {
+ double invDenom = Math.invsqrt(a * a + b * b + c * c);
+ double dist = (a * centerX + b * centerY + c * centerZ + d) * invDenom;
+ if (-radius <= dist && dist <= radius) {
+ intersectionCenterAndRadius.x = centerX + dist * a * invDenom;
+ intersectionCenterAndRadius.y = centerY + dist * b * invDenom;
+ intersectionCenterAndRadius.z = centerZ + dist * c * invDenom;
+ intersectionCenterAndRadius.w = Math.sqrt(radius * radius - dist * dist);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the moving sphere with center
+ * (cX, cY, cZ)
, radius
and velocity (vX, vY, vZ)
, and store the point of intersection
+ * in the (x, y, z)
components of the supplied vector and the time of intersection in the w component.
+ *
+ * The normal vector (a, b, c)
of the plane equation needs to be normalized.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.5.3 "Intersecting Moving Sphere Against Plane"
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param cX
+ * the x coordinate of the center position of the sphere at t=0
+ * @param cY
+ * the y coordinate of the center position of the sphere at t=0
+ * @param cZ
+ * the z coordinate of the center position of the sphere at t=0
+ * @param radius
+ * the sphere's radius
+ * @param vX
+ * the x component of the velocity of the sphere
+ * @param vY
+ * the y component of the velocity of the sphere
+ * @param vZ
+ * the z component of the velocity of the sphere
+ * @param pointAndTime
+ * will hold the point and time of intersection (if any)
+ * @return true
iff the sphere intersects the plane; false
otherwise
+ */
+ public static boolean intersectPlaneSweptSphere(
+ double a, double b, double c, double d,
+ double cX, double cY, double cZ, double radius,
+ double vX, double vY, double vZ,
+ Vector4d pointAndTime) {
+ // Compute distance of sphere center to plane
+ double dist = a * cX + b * cY + c * cZ - d;
+ if (Math.abs(dist) <= radius) {
+ // The sphere is already overlapping the plane. Set time of
+ // intersection to zero and q to sphere center
+ pointAndTime.set(cX, cY, cZ, 0.0);
+ return true;
+ }
+ double denom = a * vX + b * vY + c * vZ;
+ if (denom * dist >= 0.0) {
+ // No intersection as sphere moving parallel to or away from plane
+ return false;
+ }
+ // Sphere is moving towards the plane
+ // Use +r in computations if sphere in front of plane, else -r
+ double r = dist > 0.0 ? radius : -radius;
+ double t = (r - dist) / denom;
+ pointAndTime.set(
+ cX + t * vX - r * a,
+ cY + t * vY - r * b,
+ cZ + t * vZ - r * c,
+ t);
+ return true;
+ }
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the sphere moving from center
+ * position (t0X, t0Y, t0Z)
to (t1X, t1Y, t1Z)
and having the given radius
.
+ *
+ * The normal vector (a, b, c)
of the plane equation needs to be normalized.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.5.3 "Intersecting Moving Sphere Against Plane"
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param t0X
+ * the x coordinate of the start position of the sphere
+ * @param t0Y
+ * the y coordinate of the start position of the sphere
+ * @param t0Z
+ * the z coordinate of the start position of the sphere
+ * @param r
+ * the sphere's radius
+ * @param t1X
+ * the x coordinate of the end position of the sphere
+ * @param t1Y
+ * the y coordinate of the end position of the sphere
+ * @param t1Z
+ * the z coordinate of the end position of the sphere
+ * @return true
if the sphere intersects the plane; false
otherwise
+ */
+ public static boolean testPlaneSweptSphere(
+ double a, double b, double c, double d,
+ double t0X, double t0Y, double t0Z, double r,
+ double t1X, double t1Y, double t1Z) {
+ // Get the distance for both a and b from plane p
+ double adist = t0X * a + t0Y * b + t0Z * c - d;
+ double bdist = t1X * a + t1Y * b + t1Z * c - d;
+ // Intersects if on different sides of plane (distances have different signs)
+ if (adist * bdist < 0.0) return true;
+ // Intersects if start or end position within radius from plane
+ if (Math.abs(adist) <= r || Math.abs(bdist) <= r) return true;
+ // No intersection
+ return false;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * intersects the plane with the general equation a*x + b*y + c*z + d = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the z coordinate of the maximum corner of the axis-aligned box
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return true
iff the axis-aligned box intersects the plane; false
otherwise
+ */
+ public static boolean testAabPlane(
+ double minX, double minY, double minZ,
+ double maxX, double maxY, double maxZ,
+ double a, double b, double c, double d) {
+ double pX, pY, pZ, nX, nY, nZ;
+ if (a > 0.0) {
+ pX = maxX;
+ nX = minX;
+ } else {
+ pX = minX;
+ nX = maxX;
+ }
+ if (b > 0.0) {
+ pY = maxY;
+ nY = minY;
+ } else {
+ pY = minY;
+ nY = maxY;
+ }
+ if (c > 0.0) {
+ pZ = maxZ;
+ nZ = minZ;
+ } else {
+ pZ = minZ;
+ nZ = maxZ;
+ }
+ double distN = d + a * nX + b * nY + c * nZ;
+ double distP = d + a * pX + b * pY + c * pZ;
+ return distN <= 0.0 && distP >= 0.0;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner min
and maximum corner max
+ * intersects the plane with the general equation a*x + b*y + c*z + d = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return true
iff the axis-aligned box intersects the plane; false
otherwise
+ */
+ public static boolean testAabPlane(Vector3dc min, Vector3dc max, double a, double b, double c, double d) {
+ return testAabPlane(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), a, b, c, d);
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner (minXA, minYA, minZA)
and maximum corner (maxXA, maxYA, maxZA)
+ * intersects the axis-aligned box with minimum corner (minXB, minYB, minZB)
and maximum corner (maxXB, maxYB, maxZB)
.
+ *
+ * @param minXA
+ * the x coordinate of the minimum corner of the first axis-aligned box
+ * @param minYA
+ * the y coordinate of the minimum corner of the first axis-aligned box
+ * @param minZA
+ * the z coordinate of the minimum corner of the first axis-aligned box
+ * @param maxXA
+ * the x coordinate of the maximum corner of the first axis-aligned box
+ * @param maxYA
+ * the y coordinate of the maximum corner of the first axis-aligned box
+ * @param maxZA
+ * the z coordinate of the maximum corner of the first axis-aligned box
+ * @param minXB
+ * the x coordinate of the minimum corner of the second axis-aligned box
+ * @param minYB
+ * the y coordinate of the minimum corner of the second axis-aligned box
+ * @param minZB
+ * the z coordinate of the minimum corner of the second axis-aligned box
+ * @param maxXB
+ * the x coordinate of the maximum corner of the second axis-aligned box
+ * @param maxYB
+ * the y coordinate of the maximum corner of the second axis-aligned box
+ * @param maxZB
+ * the z coordinate of the maximum corner of the second axis-aligned box
+ * @return true
iff both axis-aligned boxes intersect; false
otherwise
+ */
+ public static boolean testAabAab(
+ double minXA, double minYA, double minZA,
+ double maxXA, double maxYA, double maxZA,
+ double minXB, double minYB, double minZB,
+ double maxXB, double maxYB, double maxZB) {
+ return maxXA >= minXB && maxYA >= minYB && maxZA >= minZB &&
+ minXA <= maxXB && minYA <= maxYB && minZA <= maxZB;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner minA
and maximum corner maxA
+ * intersects the axis-aligned box with minimum corner minB
and maximum corner maxB
.
+ *
+ * @param minA
+ * the minimum corner of the first axis-aligned box
+ * @param maxA
+ * the maximum corner of the first axis-aligned box
+ * @param minB
+ * the minimum corner of the second axis-aligned box
+ * @param maxB
+ * the maximum corner of the second axis-aligned box
+ * @return true
iff both axis-aligned boxes intersect; false
otherwise
+ */
+ public static boolean testAabAab(Vector3dc minA, Vector3dc maxA, Vector3dc minB, Vector3dc maxB) {
+ return testAabAab(minA.x(), minA.y(), minA.z(), maxA.x(), maxA.y(), maxA.z(), minB.x(), minB.y(), minB.z(), maxB.x(), maxB.y(), maxB.z());
+ }
+
+ /**
+ * Test whether two oriented boxes given via their center position, orientation and half-size, intersect.
+ *
+ * The orientation of a box is given as three unit vectors spanning the local orthonormal basis of the box.
+ *
+ * The size is given as the half-size along each of the unit vectors defining the orthonormal basis.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 4.4.1 "OBB-OBB Intersection"
+ *
+ * @param b0c
+ * the center of the first box
+ * @param b0uX
+ * the local X unit vector of the first box
+ * @param b0uY
+ * the local Y unit vector of the first box
+ * @param b0uZ
+ * the local Z unit vector of the first box
+ * @param b0hs
+ * the half-size of the first box
+ * @param b1c
+ * the center of the second box
+ * @param b1uX
+ * the local X unit vector of the second box
+ * @param b1uY
+ * the local Y unit vector of the second box
+ * @param b1uZ
+ * the local Z unit vector of the second box
+ * @param b1hs
+ * the half-size of the second box
+ * @return true
if both boxes intersect; false
otherwise
+ */
+ public static boolean testObOb(
+ Vector3d b0c, Vector3d b0uX, Vector3d b0uY, Vector3d b0uZ, Vector3d b0hs,
+ Vector3d b1c, Vector3d b1uX, Vector3d b1uY, Vector3d b1uZ, Vector3d b1hs) {
+ return testObOb(
+ b0c.x, b0c.y, b0c.z, b0uX.x, b0uX.y, b0uX.z, b0uY.x, b0uY.y, b0uY.z, b0uZ.x, b0uZ.y, b0uZ.z, b0hs.x, b0hs.y, b0hs.z,
+ b1c.x, b1c.y, b1c.z, b1uX.x, b1uX.y, b1uX.z, b1uY.x, b1uY.y, b1uY.z, b1uZ.x, b1uZ.y, b1uZ.z, b1hs.x, b1hs.y, b1hs.z);
+ }
+
+ /**
+ * Test whether two oriented boxes given via their center position, orientation and half-size, intersect.
+ *
+ * The orientation of a box is given as three unit vectors spanning the local orthonormal basis of the box.
+ *
+ * The size is given as the half-size along each of the unit vectors defining the orthonormal basis.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 4.4.1 "OBB-OBB Intersection"
+ *
+ * @param b0cX
+ * the x coordinate of the center of the first box
+ * @param b0cY
+ * the y coordinate of the center of the first box
+ * @param b0cZ
+ * the z coordinate of the center of the first box
+ * @param b0uXx
+ * the x coordinate of the local X unit vector of the first box
+ * @param b0uXy
+ * the y coordinate of the local X unit vector of the first box
+ * @param b0uXz
+ * the z coordinate of the local X unit vector of the first box
+ * @param b0uYx
+ * the x coordinate of the local Y unit vector of the first box
+ * @param b0uYy
+ * the y coordinate of the local Y unit vector of the first box
+ * @param b0uYz
+ * the z coordinate of the local Y unit vector of the first box
+ * @param b0uZx
+ * the x coordinate of the local Z unit vector of the first box
+ * @param b0uZy
+ * the y coordinate of the local Z unit vector of the first box
+ * @param b0uZz
+ * the z coordinate of the local Z unit vector of the first box
+ * @param b0hsX
+ * the half-size of the first box along its local X axis
+ * @param b0hsY
+ * the half-size of the first box along its local Y axis
+ * @param b0hsZ
+ * the half-size of the first box along its local Z axis
+ * @param b1cX
+ * the x coordinate of the center of the second box
+ * @param b1cY
+ * the y coordinate of the center of the second box
+ * @param b1cZ
+ * the z coordinate of the center of the second box
+ * @param b1uXx
+ * the x coordinate of the local X unit vector of the second box
+ * @param b1uXy
+ * the y coordinate of the local X unit vector of the second box
+ * @param b1uXz
+ * the z coordinate of the local X unit vector of the second box
+ * @param b1uYx
+ * the x coordinate of the local Y unit vector of the second box
+ * @param b1uYy
+ * the y coordinate of the local Y unit vector of the second box
+ * @param b1uYz
+ * the z coordinate of the local Y unit vector of the second box
+ * @param b1uZx
+ * the x coordinate of the local Z unit vector of the second box
+ * @param b1uZy
+ * the y coordinate of the local Z unit vector of the second box
+ * @param b1uZz
+ * the z coordinate of the local Z unit vector of the second box
+ * @param b1hsX
+ * the half-size of the second box along its local X axis
+ * @param b1hsY
+ * the half-size of the second box along its local Y axis
+ * @param b1hsZ
+ * the half-size of the second box along its local Z axis
+ * @return true
if both boxes intersect; false
otherwise
+ */
+ public static boolean testObOb(
+ double b0cX, double b0cY, double b0cZ, double b0uXx, double b0uXy, double b0uXz, double b0uYx, double b0uYy, double b0uYz, double b0uZx, double b0uZy, double b0uZz, double b0hsX, double b0hsY, double b0hsZ,
+ double b1cX, double b1cY, double b1cZ, double b1uXx, double b1uXy, double b1uXz, double b1uYx, double b1uYy, double b1uYz, double b1uZx, double b1uZy, double b1uZz, double b1hsX, double b1hsY, double b1hsZ) {
+ double ra, rb;
+ // Compute rotation matrix expressing b in a's coordinate frame
+ double rm00 = b0uXx * b1uXx + b0uYx * b1uYx + b0uZx * b1uZx;
+ double rm10 = b0uXx * b1uXy + b0uYx * b1uYy + b0uZx * b1uZy;
+ double rm20 = b0uXx * b1uXz + b0uYx * b1uYz + b0uZx * b1uZz;
+ double rm01 = b0uXy * b1uXx + b0uYy * b1uYx + b0uZy * b1uZx;
+ double rm11 = b0uXy * b1uXy + b0uYy * b1uYy + b0uZy * b1uZy;
+ double rm21 = b0uXy * b1uXz + b0uYy * b1uYz + b0uZy * b1uZz;
+ double rm02 = b0uXz * b1uXx + b0uYz * b1uYx + b0uZz * b1uZx;
+ double rm12 = b0uXz * b1uXy + b0uYz * b1uYy + b0uZz * b1uZy;
+ double rm22 = b0uXz * b1uXz + b0uYz * b1uYz + b0uZz * b1uZz;
+ // Compute common subexpressions. Add in an epsilon term to
+ // counteract arithmetic errors when two edges are parallel and
+ // their cross product is (near) null (see text for details)
+ double EPSILON = 1E-8;
+ double arm00 = Math.abs(rm00) + EPSILON;
+ double arm01 = Math.abs(rm01) + EPSILON;
+ double arm02 = Math.abs(rm02) + EPSILON;
+ double arm10 = Math.abs(rm10) + EPSILON;
+ double arm11 = Math.abs(rm11) + EPSILON;
+ double arm12 = Math.abs(rm12) + EPSILON;
+ double arm20 = Math.abs(rm20) + EPSILON;
+ double arm21 = Math.abs(rm21) + EPSILON;
+ double arm22 = Math.abs(rm22) + EPSILON;
+ // Compute translation vector t
+ double tx = b1cX - b0cX, ty = b1cY - b0cY, tz = b1cZ - b0cZ;
+ // Bring translation into a's coordinate frame
+ double tax = tx * b0uXx + ty * b0uXy + tz * b0uXz;
+ double tay = tx * b0uYx + ty * b0uYy + tz * b0uYz;
+ double taz = tx * b0uZx + ty * b0uZy + tz * b0uZz;
+ // Test axes L = A0, L = A1, L = A2
+ ra = b0hsX;
+ rb = b1hsX * arm00 + b1hsY * arm01 + b1hsZ * arm02;
+ if (Math.abs(tax) > ra + rb) return false;
+ ra = b0hsY;
+ rb = b1hsX * arm10 + b1hsY * arm11 + b1hsZ * arm12;
+ if (Math.abs(tay) > ra + rb) return false;
+ ra = b0hsZ;
+ rb = b1hsX * arm20 + b1hsY * arm21 + b1hsZ * arm22;
+ if (Math.abs(taz) > ra + rb) return false;
+ // Test axes L = B0, L = B1, L = B2
+ ra = b0hsX * arm00 + b0hsY * arm10 + b0hsZ * arm20;
+ rb = b1hsX;
+ if (Math.abs(tax * rm00 + tay * rm10 + taz * rm20) > ra + rb) return false;
+ ra = b0hsX * arm01 + b0hsY * arm11 + b0hsZ * arm21;
+ rb = b1hsY;
+ if (Math.abs(tax * rm01 + tay * rm11 + taz * rm21) > ra + rb) return false;
+ ra = b0hsX * arm02 + b0hsY * arm12 + b0hsZ * arm22;
+ rb = b1hsZ;
+ if (Math.abs(tax * rm02 + tay * rm12 + taz * rm22) > ra + rb) return false;
+ // Test axis L = A0 x B0
+ ra = b0hsY * arm20 + b0hsZ * arm10;
+ rb = b1hsY * arm02 + b1hsZ * arm01;
+ if (Math.abs(taz * rm10 - tay * rm20) > ra + rb) return false;
+ // Test axis L = A0 x B1
+ ra = b0hsY * arm21 + b0hsZ * arm11;
+ rb = b1hsX * arm02 + b1hsZ * arm00;
+ if (Math.abs(taz * rm11 - tay * rm21) > ra + rb) return false;
+ // Test axis L = A0 x B2
+ ra = b0hsY * arm22 + b0hsZ * arm12;
+ rb = b1hsX * arm01 + b1hsY * arm00;
+ if (Math.abs(taz * rm12 - tay * rm22) > ra + rb) return false;
+ // Test axis L = A1 x B0
+ ra = b0hsX * arm20 + b0hsZ * arm00;
+ rb = b1hsY * arm12 + b1hsZ * arm11;
+ if (Math.abs(tax * rm20 - taz * rm00) > ra + rb) return false;
+ // Test axis L = A1 x B1
+ ra = b0hsX * arm21 + b0hsZ * arm01;
+ rb = b1hsX * arm12 + b1hsZ * arm10;
+ if (Math.abs(tax * rm21 - taz * rm01) > ra + rb) return false;
+ // Test axis L = A1 x B2
+ ra = b0hsX * arm22 + b0hsZ * arm02;
+ rb = b1hsX * arm11 + b1hsY * arm10;
+ if (Math.abs(tax * rm22 - taz * rm02) > ra + rb) return false;
+ // Test axis L = A2 x B0
+ ra = b0hsX * arm10 + b0hsY * arm00;
+ rb = b1hsY * arm22 + b1hsZ * arm21;
+ if (Math.abs(tay * rm00 - tax * rm10) > ra + rb) return false;
+ // Test axis L = A2 x B1
+ ra = b0hsX * arm11 + b0hsY * arm01;
+ rb = b1hsX * arm22 + b1hsZ * arm20;
+ if (Math.abs(tay * rm01 - tax * rm11) > ra + rb) return false;
+ // Test axis L = A2 x B2
+ ra = b0hsX * arm12 + b0hsY * arm02;
+ rb = b1hsX * arm21 + b1hsY * arm20;
+ if (Math.abs(tay * rm02 - tax * rm12) > ra + rb) return false;
+ // Since no separating axis is found, the OBBs must be intersecting
+ return true;
+ }
+
+ /**
+ * Test whether the one sphere with center (aX, aY, aZ)
and square radius radiusSquaredA
intersects the other
+ * sphere with center (bX, bY, bZ)
and square radius radiusSquaredB
, and store the center of the circle of
+ * intersection in the (x, y, z)
components of the supplied vector and the radius of that circle in the w component.
+ *
+ * The normal vector of the circle of intersection can simply be obtained by subtracting the center of either sphere from the other.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param aX
+ * the x coordinate of the first sphere's center
+ * @param aY
+ * the y coordinate of the first sphere's center
+ * @param aZ
+ * the z coordinate of the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param bX
+ * the x coordinate of the second sphere's center
+ * @param bY
+ * the y coordinate of the second sphere's center
+ * @param bZ
+ * the z coordinate of the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @param centerAndRadiusOfIntersectionCircle
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean intersectSphereSphere(
+ double aX, double aY, double aZ, double radiusSquaredA,
+ double bX, double bY, double bZ, double radiusSquaredB,
+ Vector4d centerAndRadiusOfIntersectionCircle) {
+ double dX = bX - aX, dY = bY - aY, dZ = bZ - aZ;
+ double distSquared = dX * dX + dY * dY + dZ * dZ;
+ double h = 0.5 + (radiusSquaredA - radiusSquaredB) / distSquared;
+ double r_i = radiusSquaredA - h * h * distSquared;
+ if (r_i >= 0.0) {
+ centerAndRadiusOfIntersectionCircle.x = aX + h * dX;
+ centerAndRadiusOfIntersectionCircle.y = aY + h * dY;
+ centerAndRadiusOfIntersectionCircle.z = aZ + h * dZ;
+ centerAndRadiusOfIntersectionCircle.w = Math.sqrt(r_i);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the one sphere with center centerA
and square radius radiusSquaredA
intersects the other
+ * sphere with center centerB
and square radius radiusSquaredB
, and store the center of the circle of
+ * intersection in the (x, y, z)
components of the supplied vector and the radius of that circle in the w component.
+ *
+ * The normal vector of the circle of intersection can simply be obtained by subtracting the center of either sphere from the other.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param centerB
+ * the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @param centerAndRadiusOfIntersectionCircle
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean intersectSphereSphere(Vector3dc centerA, double radiusSquaredA, Vector3dc centerB, double radiusSquaredB, Vector4d centerAndRadiusOfIntersectionCircle) {
+ return intersectSphereSphere(centerA.x(), centerA.y(), centerA.z(), radiusSquaredA, centerB.x(), centerB.y(), centerB.z(), radiusSquaredB, centerAndRadiusOfIntersectionCircle);
+ }
+
+ /**
+ * Test whether the given sphere with center (sX, sY, sZ)
intersects the triangle given by its three vertices, and if they intersect
+ * store the point of intersection into result
.
+ *
+ * This method also returns whether the point of intersection is on one of the triangle's vertices, edges or on the face.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.2.7 "Testing Sphere Against Triangle"
+ *
+ * @param sX
+ * the x coordinate of the sphere's center
+ * @param sY
+ * the y coordinate of the sphere's center
+ * @param sZ
+ * the z coordinate of the sphere's center
+ * @param sR
+ * the sphere's radius
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v0Z
+ * the z coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v1Z
+ * the z coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param v2Z
+ * the z coordinate of the third vertex of the triangle
+ * @param result
+ * will hold the point of intersection
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE} or 0
+ */
+ public static int intersectSphereTriangle(
+ double sX, double sY, double sZ, double sR,
+ double v0X, double v0Y, double v0Z,
+ double v1X, double v1Y, double v1Z,
+ double v2X, double v2Y, double v2Z,
+ Vector3d result) {
+ int closest = findClosestPointOnTriangle(v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, sX, sY, sZ, result);
+ double vX = result.x - sX, vY = result.y - sY, vZ = result.z - sZ;
+ double dot = vX * vX + vY * vY + vZ * vZ;
+ if (dot <= sR * sR) {
+ return closest;
+ }
+ return 0;
+ }
+
+ /**
+ * Test whether the one sphere with center (aX, aY, aZ)
and square radius radiusSquaredA
intersects the other
+ * sphere with center (bX, bY, bZ)
and square radius radiusSquaredB
.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param aX
+ * the x coordinate of the first sphere's center
+ * @param aY
+ * the y coordinate of the first sphere's center
+ * @param aZ
+ * the z coordinate of the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param bX
+ * the x coordinate of the second sphere's center
+ * @param bY
+ * the y coordinate of the second sphere's center
+ * @param bZ
+ * the z coordinate of the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean testSphereSphere(
+ double aX, double aY, double aZ, double radiusSquaredA,
+ double bX, double bY, double bZ, double radiusSquaredB) {
+ double dX = bX - aX, dY = bY - aY, dZ = bZ - aZ;
+ double distSquared = dX * dX + dY * dY + dZ * dZ;
+ double h = 0.5 + (radiusSquaredA - radiusSquaredB) / distSquared;
+ double r_i = radiusSquaredA - h * h * distSquared;
+ return r_i >= 0.0;
+ }
+
+ /**
+ * Test whether the one sphere with center centerA
and square radius radiusSquaredA
intersects the other
+ * sphere with center centerB
and square radius radiusSquaredB
.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param centerB
+ * the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean testSphereSphere(Vector3dc centerA, double radiusSquaredA, Vector3dc centerB, double radiusSquaredB) {
+ return testSphereSphere(centerA.x(), centerA.y(), centerA.z(), radiusSquaredA, centerB.x(), centerB.y(), centerB.z(), radiusSquaredB);
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY, pointZ)
to the plane specified via its general plane equation
+ * a*x + b*y + c*z + d = 0.
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param pointZ
+ * the z coordinate of the point
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return the distance between the point and the plane
+ */
+ public static double distancePointPlane(double pointX, double pointY, double pointZ, double a, double b, double c, double d) {
+ double denom = Math.sqrt(a * a + b * b + c * c);
+ return (a * pointX + b * pointY + c * pointZ + d) / denom;
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY, pointZ)
to the plane of the triangle specified by its three points
+ * (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * If the point lies on the front-facing side of the triangle's plane, that is, if the triangle has counter-clockwise winding order
+ * as seen from the point, then this method returns a positive number.
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param pointZ
+ * the z coordinate of the point
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v0Z
+ * the z coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v1Z
+ * the z coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param v2Z
+ * the z coordinate of the third vertex of the triangle
+ * @return the signed distance between the point and the plane of the triangle
+ */
+ public static double distancePointPlane(double pointX, double pointY, double pointZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z) {
+ double v1Y0Y = v1Y - v0Y;
+ double v2Z0Z = v2Z - v0Z;
+ double v2Y0Y = v2Y - v0Y;
+ double v1Z0Z = v1Z - v0Z;
+ double v2X0X = v2X - v0X;
+ double v1X0X = v1X - v0X;
+ double a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z;
+ double b = v1Z0Z * v2X0X - v2Z0Z * v1X0X;
+ double c = v1X0X * v2Y0Y - v2X0X * v1Y0Y;
+ double d = -(a * v0X + b * v0Y + c * v0Z);
+ return distancePointPlane(pointX, pointY, pointZ, a, b, c, d);
+ }
+
+ /**
+ * Test whether the ray with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
intersects the plane
+ * containing the given point (pointX, pointY, pointZ)
and having the normal (normalX, normalY, normalZ)
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the plane, because it is either parallel to the plane or its direction points
+ * away from the plane or the ray's origin is on the negative side of the plane (i.e. the plane's normal points away from the ray's origin).
+ *
+ * Reference: https://www.siggraph.org/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param pointX
+ * the x coordinate of a point on the plane
+ * @param pointY
+ * the y coordinate of a point on the plane
+ * @param pointZ
+ * the z coordinate of a point on the plane
+ * @param normalX
+ * the x coordinate of the plane's normal
+ * @param normalY
+ * the y coordinate of the plane's normal
+ * @param normalZ
+ * the z coordinate of the plane's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the plane
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the plane; -1.0
otherwise
+ */
+ public static double intersectRayPlane(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double pointX, double pointY, double pointZ, double normalX, double normalY, double normalZ, double epsilon) {
+ double denom = normalX * dirX + normalY * dirY + normalZ * dirZ;
+ if (denom < epsilon) {
+ double t = ((pointX - originX) * normalX + (pointY - originY) * normalY + (pointZ - originZ) * normalZ) / denom;
+ if (t >= 0.0)
+ return t;
+ }
+ return -1.0;
+ }
+
+ /**
+ * Test whether the ray with given origin
and direction dir
intersects the plane
+ * containing the given point
and having the given normal
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the plane, because it is either parallel to the plane or its direction points
+ * away from the plane or the ray's origin is on the negative side of the plane (i.e. the plane's normal points away from the ray's origin).
+ *
+ * Reference: https://www.siggraph.org/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param point
+ * a point on the plane
+ * @param normal
+ * the plane's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the plane
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the plane; -1.0
otherwise
+ */
+ public static double intersectRayPlane(Vector3dc origin, Vector3dc dir, Vector3dc point, Vector3dc normal, double epsilon) {
+ return intersectRayPlane(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), point.x(), point.y(), point.z(), normal.x(), normal.y(), normal.z(), epsilon);
+ }
+
+ /**
+ * Test whether the ray with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
intersects the plane
+ * given as the general plane equation a*x + b*y + c*z + d = 0, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the plane, because it is either parallel to the plane or its direction points
+ * away from the plane or the ray's origin is on the negative side of the plane (i.e. the plane's normal points away from the ray's origin).
+ *
+ * Reference: https://www.siggraph.org/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the plane
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the plane; -1.0
otherwise
+ */
+ public static double intersectRayPlane(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double a, double b, double c, double d, double epsilon) {
+ double denom = a * dirX + b * dirY + c * dirZ;
+ if (denom < 0.0) {
+ double t = -(a * originX + b * originY + c * originZ + d) / denom;
+ if (t >= 0.0)
+ return t;
+ }
+ return -1.0;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * intersects the sphere with the given center (centerX, centerY, centerZ)
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the z coordinate of the maximum corner of the axis-aligned box
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the square of the sphere's radius
+ * @return true
iff the axis-aligned box intersects the sphere; false
otherwise
+ */
+ public static boolean testAabSphere(
+ double minX, double minY, double minZ,
+ double maxX, double maxY, double maxZ,
+ double centerX, double centerY, double centerZ, double radiusSquared) {
+ double radius2 = radiusSquared;
+ if (centerX < minX) {
+ double d = (centerX - minX);
+ radius2 -= d * d;
+ } else if (centerX > maxX) {
+ double d = (centerX - maxX);
+ radius2 -= d * d;
+ }
+ if (centerY < minY) {
+ double d = (centerY - minY);
+ radius2 -= d * d;
+ } else if (centerY > maxY) {
+ double d = (centerY - maxY);
+ radius2 -= d * d;
+ }
+ if (centerZ < minZ) {
+ double d = (centerZ - minZ);
+ radius2 -= d * d;
+ } else if (centerZ > maxZ) {
+ double d = (centerZ - maxZ);
+ radius2 -= d * d;
+ }
+ return radius2 >= 0.0;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner min
and maximum corner max
+ * intersects the sphere with the given center
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the squared of the sphere's radius
+ * @return true
iff the axis-aligned box intersects the sphere; false
otherwise
+ */
+ public static boolean testAabSphere(Vector3dc min, Vector3dc max, Vector3dc center, double radiusSquared) {
+ return testAabSphere(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), center.x(), center.y(), center.z(), radiusSquared);
+ }
+
+ /**
+ * Find the point on the given plane which is closest to the specified point (pX, pY, pZ)
and store the result in result
.
+ *
+ * @param aX
+ * the x coordinate of one point on the plane
+ * @param aY
+ * the y coordinate of one point on the plane
+ * @param aZ
+ * the z coordinate of one point on the plane
+ * @param nX
+ * the x coordinate of the unit normal of the plane
+ * @param nY
+ * the y coordinate of the unit normal of the plane
+ * @param nZ
+ * the z coordinate of the unit normal of the plane
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param result
+ * will hold the result
+ * @return result
+ */
+ public static Vector3d findClosestPointOnPlane(double aX, double aY, double aZ, double nX, double nY, double nZ, double pX, double pY, double pZ, Vector3d result) {
+ double d = -(nX * aX + nY * aY + nZ * aZ);
+ double t = nX * pX + nY * pY + nZ * pZ - d;
+ result.x = pX - t * nX;
+ result.y = pY - t * nY;
+ result.z = pZ - t * nZ;
+ return result;
+ }
+
+ /**
+ * Find the point on the given line segment which is closest to the specified point (pX, pY, pZ)
, and store the result in result
.
+ *
+ * @param aX
+ * the x coordinate of the first end point of the line segment
+ * @param aY
+ * the y coordinate of the first end point of the line segment
+ * @param aZ
+ * the z coordinate of the first end point of the line segment
+ * @param bX
+ * the x coordinate of the second end point of the line segment
+ * @param bY
+ * the y coordinate of the second end point of the line segment
+ * @param bZ
+ * the z coordinate of the second end point of the line segment
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param result
+ * will hold the result
+ * @return result
+ */
+ public static Vector3d findClosestPointOnLineSegment(double aX, double aY, double aZ, double bX, double bY, double bZ, double pX, double pY, double pZ, Vector3d result) {
+ double abX = bX - aX, abY = bY - aY, abZ = bZ - aZ;
+ double t = ((pX - aX) * abX + (pY - aY) * abY + (pZ - aZ) * abZ) / (abX * abX + abY * abY + abZ * abZ);
+ if (t < 0.0) t = 0.0;
+ if (t > 1.0) t = 1.0;
+ result.x = aX + t * abX;
+ result.y = aY + t * abY;
+ result.z = aZ + t * abZ;
+ return result;
+ }
+
+ /**
+ * Find the closest points on the two line segments, store the point on the first line segment in resultA
and
+ * the point on the second line segment in resultB
, and return the square distance between both points.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.9 "Closest Points of Two Line Segments"
+ *
+ * @param a0X
+ * the x coordinate of the first line segment's first end point
+ * @param a0Y
+ * the y coordinate of the first line segment's first end point
+ * @param a0Z
+ * the z coordinate of the first line segment's first end point
+ * @param a1X
+ * the x coordinate of the first line segment's second end point
+ * @param a1Y
+ * the y coordinate of the first line segment's second end point
+ * @param a1Z
+ * the z coordinate of the first line segment's second end point
+ * @param b0X
+ * the x coordinate of the second line segment's first end point
+ * @param b0Y
+ * the y coordinate of the second line segment's first end point
+ * @param b0Z
+ * the z coordinate of the second line segment's first end point
+ * @param b1X
+ * the x coordinate of the second line segment's second end point
+ * @param b1Y
+ * the y coordinate of the second line segment's second end point
+ * @param b1Z
+ * the z coordinate of the second line segment's second end point
+ * @param resultA
+ * will hold the point on the first line segment
+ * @param resultB
+ * will hold the point on the second line segment
+ * @return the square distance between the two closest points
+ */
+ public static double findClosestPointsLineSegments(
+ double a0X, double a0Y, double a0Z, double a1X, double a1Y, double a1Z,
+ double b0X, double b0Y, double b0Z, double b1X, double b1Y, double b1Z,
+ Vector3d resultA, Vector3d resultB) {
+ double d1x = a1X - a0X, d1y = a1Y - a0Y, d1z = a1Z - a0Z;
+ double d2x = b1X - b0X, d2y = b1Y - b0Y, d2z = b1Z - b0Z;
+ double rX = a0X - b0X, rY = a0Y - b0Y, rZ = a0Z - b0Z;
+ double a = d1x * d1x + d1y * d1y + d1z * d1z;
+ double e = d2x * d2x + d2y * d2y + d2z * d2z;
+ double f = d2x * rX + d2y * rY + d2z * rZ;
+ double EPSILON = 1E-8;
+ double s, t;
+ if (a <= EPSILON && e <= EPSILON) {
+ // Both segments degenerate into points
+ resultA.set(a0X, a0Y, a0Z);
+ resultB.set(b0X, b0Y, b0Z);
+ return resultA.dot(resultB);
+ }
+ if (a <= EPSILON) {
+ // First segment degenerates into a point
+ s = 0.0;
+ t = f / e;
+ t = Math.min(Math.max(t, 0.0), 1.0);
+ } else {
+ double c = d1x * rX + d1y * rY + d1z * rZ;
+ if (e <= EPSILON) {
+ // Second segment degenerates into a point
+ t = 0.0;
+ s = Math.min(Math.max(-c / a, 0.0), 1.0);
+ } else {
+ // The general nondegenerate case starts here
+ double b = d1x * d2x + d1y * d2y + d1z * d2z;
+ double denom = a * e - b * b;
+ // If segments not parallel, compute closest point on L1 to L2 and
+ // clamp to segment S1. Else pick arbitrary s (here 0)
+ if (denom != 0.0)
+ s = Math.min(Math.max((b*f - c*e) / denom, 0.0), 1.0);
+ else
+ s = 0.0;
+ // Compute point on L2 closest to S1(s) using
+ // t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e
+ t = (b * s + f) / e;
+ // If t in [0,1] done. Else clamp t, recompute s for the new value
+ // of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a
+ // and clamp s to [0, 1]
+ if (t < 0.0) {
+ t = 0.0;
+ s = Math.min(Math.max(-c / a, 0.0), 1.0);
+ } else if (t > 1.0) {
+ t = 1.0;
+ s = Math.min(Math.max((b - c) / a, 0.0), 1.0);
+ }
+ }
+ }
+ resultA.set(a0X + d1x * s, a0Y + d1y * s, a0Z + d1z * s);
+ resultB.set(b0X + d2x * t, b0Y + d2y * t, b0Z + d2z * t);
+ double dX = resultA.x - resultB.x, dY = resultA.y - resultB.y, dZ = resultA.z - resultB.z;
+ return dX*dX + dY*dY + dZ*dZ;
+ }
+
+ /**
+ * Find the closest points on a line segment and a triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.10 "Closest Points of a Line Segment and a Triangle"
+ *
+ * @param aX
+ * the x coordinate of the line segment's first end point
+ * @param aY
+ * the y coordinate of the line segment's first end point
+ * @param aZ
+ * the z coordinate of the line segment's first end point
+ * @param bX
+ * the x coordinate of the line segment's second end point
+ * @param bY
+ * the y coordinate of the line segment's second end point
+ * @param bZ
+ * the z coordinate of the line segment's second end point
+ * @param v0X
+ * the x coordinate of the triangle's first vertex
+ * @param v0Y
+ * the y coordinate of the triangle's first vertex
+ * @param v0Z
+ * the z coordinate of the triangle's first vertex
+ * @param v1X
+ * the x coordinate of the triangle's second vertex
+ * @param v1Y
+ * the y coordinate of the triangle's second vertex
+ * @param v1Z
+ * the z coordinate of the triangle's second vertex
+ * @param v2X
+ * the x coordinate of the triangle's third vertex
+ * @param v2Y
+ * the y coordinate of the triangle's third vertex
+ * @param v2Z
+ * the z coordinate of the triangle's third vertex
+ * @param lineSegmentResult
+ * will hold the closest point on the line segment
+ * @param triangleResult
+ * will hold the closest point on the triangle
+ * @return the square distance of the closest points
+ */
+ public static double findClosestPointsLineSegmentTriangle(
+ double aX, double aY, double aZ, double bX, double bY, double bZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ Vector3d lineSegmentResult, Vector3d triangleResult) {
+ double min, d;
+ double minlsX, minlsY, minlsZ, mintX, mintY, mintZ;
+ // AB -> V0V1
+ d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, lineSegmentResult, triangleResult);
+ min = d;
+ minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z;
+ mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z;
+ // AB -> V1V2
+ d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v1X, v1Y, v1Z, v2X, v2Y, v2Z, lineSegmentResult, triangleResult);
+ if (d < min) {
+ min = d;
+ minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z;
+ mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z;
+ }
+ // AB -> V2V0
+ d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v2X, v2Y, v2Z, v0X, v0Y, v0Z, lineSegmentResult, triangleResult);
+ if (d < min) {
+ min = d;
+ minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z;
+ mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z;
+ }
+ // segment endpoint A and plane of triangle (when A projects inside V0V1V2)
+ boolean computed = false;
+ double a = Double.NaN, b = Double.NaN, c = Double.NaN, nd = Double.NaN;
+ if (testPointInTriangle(aX, aY, aZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z)) {
+ double v1Y0Y = v1Y - v0Y;
+ double v2Z0Z = v2Z - v0Z;
+ double v2Y0Y = v2Y - v0Y;
+ double v1Z0Z = v1Z - v0Z;
+ double v2X0X = v2X - v0X;
+ double v1X0X = v1X - v0X;
+ a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z;
+ b = v1Z0Z * v2X0X - v2Z0Z * v1X0X;
+ c = v1X0X * v2Y0Y - v2X0X * v1Y0Y;
+ computed = true;
+ double invLen = Math.invsqrt(a*a + b*b + c*c);
+ a *= invLen; b *= invLen; c *= invLen;
+ nd = -(a * v0X + b * v0Y + c * v0Z);
+ d = (a * aX + b * aY + c * aZ + nd);
+ double l = d;
+ d *= d;
+ if (d < min) {
+ min = d;
+ minlsX = aX; minlsY = aY; minlsZ = aZ;
+ mintX = aX - a*l; mintY = aY - b*l; mintZ = aZ - c*l;
+ }
+ }
+ // segment endpoint B and plane of triangle (when B projects inside V0V1V2)
+ if (testPointInTriangle(bX, bY, bZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z)) {
+ if (!computed) {
+ double v1Y0Y = v1Y - v0Y;
+ double v2Z0Z = v2Z - v0Z;
+ double v2Y0Y = v2Y - v0Y;
+ double v1Z0Z = v1Z - v0Z;
+ double v2X0X = v2X - v0X;
+ double v1X0X = v1X - v0X;
+ a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z;
+ b = v1Z0Z * v2X0X - v2Z0Z * v1X0X;
+ c = v1X0X * v2Y0Y - v2X0X * v1Y0Y;
+ double invLen = Math.invsqrt(a*a + b*b + c*c);
+ a *= invLen; b *= invLen; c *= invLen;
+ nd = -(a * v0X + b * v0Y + c * v0Z);
+ }
+ d = (a * bX + b * bY + c * bZ + nd);
+ double l = d;
+ d *= d;
+ if (d < min) {
+ min = d;
+ minlsX = bX; minlsY = bY; minlsZ = bZ;
+ mintX = bX - a*l; mintY = bY - b*l; mintZ = bZ - c*l;
+ }
+ }
+ lineSegmentResult.set(minlsX, minlsY, minlsZ);
+ triangleResult.set(mintX, mintY, mintZ);
+ return min;
+ }
+
+ /**
+ * Determine the closest point on the triangle with the given vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
, (v2X, v2Y, v2Z)
+ * between that triangle and the given point (pX, pY, pZ)
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v0Z
+ * the z coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v1Z
+ * the z coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param v2Z
+ * the z coordinate of the third vertex of the triangle
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the y coordinate of the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(
+ double v0X, double v0Y, double v0Z,
+ double v1X, double v1Y, double v1Z,
+ double v2X, double v2Y, double v2Z,
+ double pX, double pY, double pZ,
+ Vector3d result) {
+ double abX = v1X - v0X, abY = v1Y - v0Y, abZ = v1Z - v0Z;
+ double acX = v2X - v0X, acY = v2Y - v0Y, acZ = v2Z - v0Z;
+ double apX = pX - v0X, apY = pY - v0Y, apZ = pZ - v0Z;
+ double d1 = abX * apX + abY * apY + abZ * apZ;
+ double d2 = acX * apX + acY * apY + acZ * apZ;
+ if (d1 <= 0.0 && d2 <= 0.0) {
+ result.x = v0X;
+ result.y = v0Y;
+ result.z = v0Z;
+ return POINT_ON_TRIANGLE_VERTEX_0;
+ }
+ double bpX = pX - v1X, bpY = pY - v1Y, bpZ = pZ - v1Z;
+ double d3 = abX * bpX + abY * bpY + abZ * bpZ;
+ double d4 = acX * bpX + acY * bpY + acZ * bpZ;
+ if (d3 >= 0.0 && d4 <= d3) {
+ result.x = v1X;
+ result.y = v1Y;
+ result.z = v1Z;
+ return POINT_ON_TRIANGLE_VERTEX_1;
+ }
+ double vc = d1 * d4 - d3 * d2;
+ if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) {
+ double v = d1 / (d1 - d3);
+ result.x = v0X + v * abX;
+ result.y = v0Y + v * abY;
+ result.z = v0Z + v * abZ;
+ return POINT_ON_TRIANGLE_EDGE_01;
+ }
+ double cpX = pX - v2X, cpY = pY - v2Y, cpZ = pZ - v2Z;
+ double d5 = abX * cpX + abY * cpY + abZ * cpZ;
+ double d6 = acX * cpX + acY * cpY + acZ * cpZ;
+ if (d6 >= 0.0 && d5 <= d6) {
+ result.x = v2X;
+ result.y = v2Y;
+ result.z = v2Z;
+ return POINT_ON_TRIANGLE_VERTEX_2;
+ }
+ double vb = d5 * d2 - d1 * d6;
+ if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) {
+ double w = d2 / (d2 - d6);
+ result.x = v0X + w * acX;
+ result.y = v0Y + w * acY;
+ result.z = v0Z + w * acZ;
+ return POINT_ON_TRIANGLE_EDGE_20;
+ }
+ double va = d3 * d6 - d5 * d4;
+ if (va <= 0.0 && d4 - d3 >= 0.0 && d5 - d6 >= 0.0) {
+ double w = (d4 - d3) / (d4 - d3 + d5 - d6);
+ result.x = v1X + w * (v2X - v1X);
+ result.y = v1Y + w * (v2Y - v1Y);
+ result.z = v1Z + w * (v2Z - v1Z);
+ return POINT_ON_TRIANGLE_EDGE_12;
+ }
+ double denom = 1.0 / (va + vb + vc);
+ double v = vb * denom;
+ double w = vc * denom;
+ result.x = v0X + abX * v + acX * w;
+ result.y = v0Y + abY * v + acY * w;
+ result.z = v0Z + abZ * v + acZ * w;
+ return POINT_ON_TRIANGLE_FACE;
+ }
+
+ /**
+ * Determine the closest point on the triangle with the vertices v0
, v1
, v2
+ * between that triangle and the given point p
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @param p
+ * the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(Vector3dc v0, Vector3dc v1, Vector3dc v2, Vector3dc p, Vector3d result) {
+ return findClosestPointOnTriangle(v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), p.x(), p.y(), p.z(), result);
+ }
+
+ /**
+ * Find the point on a given rectangle, specified via three of its corners, which is closest to the specified point
+ * (pX, pY, pZ)
and store the result into res
.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.4.2 "Closest Point on 3D Rectangle to Point"
+ *
+ * @param aX
+ * the x coordinate of the first corner point of the rectangle
+ * @param aY
+ * the y coordinate of the first corner point of the rectangle
+ * @param aZ
+ * the z coordinate of the first corner point of the rectangle
+ * @param bX
+ * the x coordinate of the second corner point of the rectangle
+ * @param bY
+ * the y coordinate of the second corner point of the rectangle
+ * @param bZ
+ * the z coordinate of the second corner point of the rectangle
+ * @param cX
+ * the x coordinate of the third corner point of the rectangle
+ * @param cY
+ * the y coordinate of the third corner point of the rectangle
+ * @param cZ
+ * the z coordinate of the third corner point of the rectangle
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param res
+ * will hold the result
+ * @return res
+ */
+ public static Vector3d findClosestPointOnRectangle(
+ double aX, double aY, double aZ,
+ double bX, double bY, double bZ,
+ double cX, double cY, double cZ,
+ double pX, double pY, double pZ, Vector3d res) {
+ double abX = bX - aX, abY = bY - aY, abZ = bZ - aZ;
+ double acX = cX - aX, acY = cY - aY, acZ = cZ - aZ;
+ double dX = pX - aX, dY = pY - aY, dZ = pZ - aZ;
+ double qX = aX, qY = aY, qZ = aZ;
+ double dist = dX * abX + dY * abY + dZ * abZ;
+ double maxdist = abX * abX + abY * abY + abZ * abZ;
+ if (dist >= maxdist) {
+ qX += abX;
+ qY += abY;
+ qZ += abZ;
+ } else if (dist > 0.0) {
+ qX += (dist / maxdist) * abX;
+ qY += (dist / maxdist) * abY;
+ qZ += (dist / maxdist) * abZ;
+ }
+ dist = dX * acX + dY * acY + dZ * acZ;
+ maxdist = acX * acX + acY * acY + acZ * acZ;
+ if (dist >= maxdist) {
+ qX += acX;
+ qY += acY;
+ qZ += acZ;
+ } else if (dist > 0.0) {
+ qX += (dist / maxdist) * acX;
+ qY += (dist / maxdist) * acY;
+ qZ += (dist / maxdist) * acZ;
+ }
+ res.x = qX;
+ res.y = qY;
+ res.z = qZ;
+ return res;
+ }
+
+ /**
+ * Determine the point of intersection between a sphere with the given center (centerX, centerY, centerZ)
and radius
moving
+ * with the given velocity (velX, velY, velZ)
and the triangle specified via its three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
, (v2X, v2Y, v2Z)
.
+ *
+ * The vertices of the triangle must be specified in counter-clockwise winding order.
+ *
+ * An intersection is only considered if the time of intersection is smaller than the given maxT
value.
+ *
+ * Reference: Improved Collision detection and Response
+ *
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radius
+ * the radius of the sphere
+ * @param velX
+ * the x component of the velocity of the sphere
+ * @param velY
+ * the y component of the velocity of the sphere
+ * @param velZ
+ * the z component of the velocity of the sphere
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param v0Z
+ * the z coordinate of the first triangle vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param v1Z
+ * the z coordinate of the second triangle vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param v2Z
+ * the z coordinate of the third triangle vertex
+ * @param epsilon
+ * a small epsilon when testing spheres that move almost parallel to the triangle
+ * @param maxT
+ * the maximum intersection time
+ * @param pointAndTime
+ * iff the moving sphere and the triangle intersect, this will hold the point of intersection in the (x, y, z)
components
+ * and the time of intersection in the w
component
+ * @return {@link #POINT_ON_TRIANGLE_FACE} if the intersection point lies on the triangle's face,
+ * or {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1} or {@link #POINT_ON_TRIANGLE_VERTEX_2} if the intersection point is a vertex,
+ * or {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12} or {@link #POINT_ON_TRIANGLE_EDGE_20} if the intersection point lies on an edge;
+ * or 0
if no intersection
+ */
+ public static int intersectSweptSphereTriangle(
+ double centerX, double centerY, double centerZ, double radius, double velX, double velY, double velZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon, double maxT, Vector4d pointAndTime) {
+ double v10X = v1X - v0X;
+ double v10Y = v1Y - v0Y;
+ double v10Z = v1Z - v0Z;
+ double v20X = v2X - v0X;
+ double v20Y = v2Y - v0Y;
+ double v20Z = v2Z - v0Z;
+ // build triangle plane
+ double a = v10Y * v20Z - v20Y * v10Z;
+ double b = v10Z * v20X - v20Z * v10X;
+ double c = v10X * v20Y - v20X * v10Y;
+ double d = -(a * v0X + b * v0Y + c * v0Z);
+ double invLen = Math.invsqrt(a * a + b * b + c * c);
+ double signedDist = (a * centerX + b * centerY + c * centerZ + d) * invLen;
+ double dot = (a * velX + b * velY + c * velZ) * invLen;
+ if (dot < epsilon && dot > -epsilon)
+ return 0;
+ double pt0 = (radius - signedDist) / dot;
+ if (pt0 > maxT)
+ return 0;
+ double pt1 = (-radius - signedDist) / dot;
+ double p0X = centerX - radius * a * invLen + velX * pt0;
+ double p0Y = centerY - radius * b * invLen + velY * pt0;
+ double p0Z = centerZ - radius * c * invLen + velZ * pt0;
+ boolean insideTriangle = testPointInTriangle(p0X, p0Y, p0Z, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z);
+ if (insideTriangle) {
+ pointAndTime.x = p0X;
+ pointAndTime.y = p0Y;
+ pointAndTime.z = p0Z;
+ pointAndTime.w = pt0;
+ return POINT_ON_TRIANGLE_FACE;
+ }
+ int isect = 0;
+ double t0 = maxT;
+ double A = velX * velX + velY * velY + velZ * velZ;
+ double radius2 = radius * radius;
+ // test against v0
+ double centerV0X = centerX - v0X;
+ double centerV0Y = centerY - v0Y;
+ double centerV0Z = centerZ - v0Z;
+ double B0 = 2.0 * (velX * centerV0X + velY * centerV0Y + velZ * centerV0Z);
+ double C0 = centerV0X * centerV0X + centerV0Y * centerV0Y + centerV0Z * centerV0Z - radius2;
+ double root0 = computeLowestRoot(A, B0, C0, t0);
+ if (root0 < t0) {
+ pointAndTime.x = v0X;
+ pointAndTime.y = v0Y;
+ pointAndTime.z = v0Z;
+ pointAndTime.w = root0;
+ t0 = root0;
+ isect = POINT_ON_TRIANGLE_VERTEX_0;
+ }
+ // test against v1
+ double centerV1X = centerX - v1X;
+ double centerV1Y = centerY - v1Y;
+ double centerV1Z = centerZ - v1Z;
+ double centerV1Len = centerV1X * centerV1X + centerV1Y * centerV1Y + centerV1Z * centerV1Z;
+ double B1 = 2.0 * (velX * centerV1X + velY * centerV1Y + velZ * centerV1Z);
+ double C1 = centerV1Len - radius2;
+ double root1 = computeLowestRoot(A, B1, C1, t0);
+ if (root1 < t0) {
+ pointAndTime.x = v1X;
+ pointAndTime.y = v1Y;
+ pointAndTime.z = v1Z;
+ pointAndTime.w = root1;
+ t0 = root1;
+ isect = POINT_ON_TRIANGLE_VERTEX_1;
+ }
+ // test against v2
+ double centerV2X = centerX - v2X;
+ double centerV2Y = centerY - v2Y;
+ double centerV2Z = centerZ - v2Z;
+ double B2 = 2.0 * (velX * centerV2X + velY * centerV2Y + velZ * centerV2Z);
+ double C2 = centerV2X * centerV2X + centerV2Y * centerV2Y + centerV2Z * centerV2Z - radius2;
+ double root2 = computeLowestRoot(A, B2, C2, t0);
+ if (root2 < t0) {
+ pointAndTime.x = v2X;
+ pointAndTime.y = v2Y;
+ pointAndTime.z = v2Z;
+ pointAndTime.w = root2;
+ t0 = root2;
+ isect = POINT_ON_TRIANGLE_VERTEX_2;
+ }
+ double velLen = velX * velX + velY * velY + velZ * velZ;
+ // test against edge10
+ double len10 = v10X * v10X + v10Y * v10Y + v10Z * v10Z;
+ double baseTo0Len = centerV0X * centerV0X + centerV0Y * centerV0Y + centerV0Z * centerV0Z;
+ double v10Vel = (v10X * velX + v10Y * velY + v10Z * velZ);
+ double A10 = len10 * -velLen + v10Vel * v10Vel;
+ double v10BaseTo0 = v10X * -centerV0X + v10Y * -centerV0Y + v10Z * -centerV0Z;
+ double velBaseTo0 = velX * -centerV0X + velY * -centerV0Y + velZ * -centerV0Z;
+ double B10 = len10 * 2 * velBaseTo0 - 2 * v10Vel * v10BaseTo0;
+ double C10 = len10 * (radius2 - baseTo0Len) + v10BaseTo0 * v10BaseTo0;
+ double root10 = computeLowestRoot(A10, B10, C10, t0);
+ double f10 = (v10Vel * root10 - v10BaseTo0) / len10;
+ if (f10 >= 0.0 && f10 <= 1.0 && root10 < t0) {
+ pointAndTime.x = v0X + f10 * v10X;
+ pointAndTime.y = v0Y + f10 * v10Y;
+ pointAndTime.z = v0Z + f10 * v10Z;
+ pointAndTime.w = root10;
+ t0 = root10;
+ isect = POINT_ON_TRIANGLE_EDGE_01;
+ }
+ // test against edge20
+ double len20 = v20X * v20X + v20Y * v20Y + v20Z * v20Z;
+ double v20Vel = (v20X * velX + v20Y * velY + v20Z * velZ);
+ double A20 = len20 * -velLen + v20Vel * v20Vel;
+ double v20BaseTo0 = v20X * -centerV0X + v20Y * -centerV0Y + v20Z * -centerV0Z;
+ double B20 = len20 * 2 * velBaseTo0 - 2 * v20Vel * v20BaseTo0;
+ double C20 = len20 * (radius2 - baseTo0Len) + v20BaseTo0 * v20BaseTo0;
+ double root20 = computeLowestRoot(A20, B20, C20, t0);
+ double f20 = (v20Vel * root20 - v20BaseTo0) / len20;
+ if (f20 >= 0.0 && f20 <= 1.0 && root20 < pt1) {
+ pointAndTime.x = v0X + f20 * v20X;
+ pointAndTime.y = v0Y + f20 * v20Y;
+ pointAndTime.z = v0Z + f20 * v20Z;
+ pointAndTime.w = root20;
+ t0 = root20;
+ isect = POINT_ON_TRIANGLE_EDGE_20;
+ }
+ // test against edge21
+ double v21X = v2X - v1X;
+ double v21Y = v2Y - v1Y;
+ double v21Z = v2Z - v1Z;
+ double len21 = v21X * v21X + v21Y * v21Y + v21Z * v21Z;
+ double baseTo1Len = centerV1Len;
+ double v21Vel = (v21X * velX + v21Y * velY + v21Z * velZ);
+ double A21 = len21 * -velLen + v21Vel * v21Vel;
+ double v21BaseTo1 = v21X * -centerV1X + v21Y * -centerV1Y + v21Z * -centerV1Z;
+ double velBaseTo1 = velX * -centerV1X + velY * -centerV1Y + velZ * -centerV1Z;
+ double B21 = len21 * 2 * velBaseTo1 - 2 * v21Vel * v21BaseTo1;
+ double C21 = len21 * (radius2 - baseTo1Len) + v21BaseTo1 * v21BaseTo1;
+ double root21 = computeLowestRoot(A21, B21, C21, t0);
+ double f21 = (v21Vel * root21 - v21BaseTo1) / len21;
+ if (f21 >= 0.0 && f21 <= 1.0 && root21 < t0) {
+ pointAndTime.x = v1X + f21 * v21X;
+ pointAndTime.y = v1Y + f21 * v21Y;
+ pointAndTime.z = v1Z + f21 * v21Z;
+ pointAndTime.w = root21;
+ t0 = root21;
+ isect = POINT_ON_TRIANGLE_EDGE_12;
+ }
+ return isect;
+ }
+
+ /**
+ * Compute the lowest root for t
in the quadratic equation a*t*t + b*t + c = 0
.
+ *
+ * This is a helper method for {@link #intersectSweptSphereTriangle}
+ *
+ * @param a
+ * the quadratic factor
+ * @param b
+ * the linear factor
+ * @param c
+ * the constant
+ * @param maxR
+ * the maximum expected root
+ * @return the lowest of the two roots of the quadratic equation; or {@link Double#POSITIVE_INFINITY}
+ */
+ private static double computeLowestRoot(double a, double b, double c, double maxR) {
+ double determinant = b * b - 4.0 * a * c;
+ if (determinant < 0.0)
+ return Double.POSITIVE_INFINITY;
+ double sqrtD = Math.sqrt(determinant);
+ double r1 = (-b - sqrtD) / (2.0 * a);
+ double r2 = (-b + sqrtD) / (2.0 * a);
+ if (r1 > r2) {
+ double temp = r2;
+ r2 = r1;
+ r1 = temp;
+ }
+ if (r1 > 0.0 && r1 < maxR) {
+ return r1;
+ }
+ if (r2 > 0.0 && r2 < maxR) {
+ return r2;
+ }
+ return Double.POSITIVE_INFINITY;
+ }
+
+ /**
+ * Test whether the projection of the given point (pX, pY, pZ)
lies inside of the triangle defined by the three vertices
+ * (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * Reference: Improved Collision detection and Response
+ *
+ * @param pX
+ * the x coordinate of the point to test
+ * @param pY
+ * the y coordinate of the point to test
+ * @param pZ
+ * the z coordinate of the point to test
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @return true
if the projection of the given point lies inside of the given triangle; false
otherwise
+ */
+ public static boolean testPointInTriangle(double pX, double pY, double pZ, double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z) {
+ double e10X = v1X - v0X;
+ double e10Y = v1Y - v0Y;
+ double e10Z = v1Z - v0Z;
+ double e20X = v2X - v0X;
+ double e20Y = v2Y - v0Y;
+ double e20Z = v2Z - v0Z;
+ double a = e10X * e10X + e10Y * e10Y + e10Z * e10Z;
+ double b = e10X * e20X + e10Y * e20Y + e10Z * e20Z;
+ double c = e20X * e20X + e20Y * e20Y + e20Z * e20Z;
+ double ac_bb = a * c - b * b;
+ double vpX = pX - v0X;
+ double vpY = pY - v0Y;
+ double vpZ = pZ - v0Z;
+ double d = vpX * e10X + vpY * e10Y + vpZ * e10Z;
+ double e = vpX * e20X + vpY * e20Y + vpZ * e20Z;
+ double x = d * c - e * b;
+ double y = e * a - d * b;
+ double z = x + y - ac_bb;
+ return ((Runtime.doubleToLongBits(z) & ~(Runtime.doubleToLongBits(x) | Runtime.doubleToLongBits(y))) & 0x8000000000000000L) != 0L;
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and normalized direction (dirX, dirY, dirZ)
+ * intersects the given sphere with center (centerX, centerY, centerZ)
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's normalized direction
+ * @param dirY
+ * the y coordinate of the ray's normalized direction
+ * @param dirZ
+ * the z coordinate of the ray's normalized direction
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the sphere
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean intersectRaySphere(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double centerX, double centerY, double centerZ, double radiusSquared, Vector2d result) {
+ double Lx = centerX - originX;
+ double Ly = centerY - originY;
+ double Lz = centerZ - originZ;
+ double tca = Lx * dirX + Ly * dirY + Lz * dirZ;
+ double d2 = Lx * Lx + Ly * Ly + Lz * Lz - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ double thc = Math.sqrt(radiusSquared - d2);
+ double t0 = tca - thc;
+ double t1 = tca + thc;
+ if (t0 < t1 && t1 >= 0.0) {
+ result.x = t0;
+ result.y = t1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and normalized direction dir
+ * intersects the sphere with the given center
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's normalized direction
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the sphere
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean intersectRaySphere(Vector3dc origin, Vector3dc dir, Vector3dc center, double radiusSquared, Vector2d result) {
+ return intersectRaySphere(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), center.x(), center.y(), center.z(), radiusSquared, result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and normalized direction (dirX, dirY, dirZ)
+ * intersects the given sphere with center (centerX, centerY, centerZ)
and square radius radiusSquared
.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's normalized direction
+ * @param dirY
+ * the y coordinate of the ray's normalized direction
+ * @param dirZ
+ * the z coordinate of the ray's normalized direction
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean testRaySphere(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double centerX, double centerY, double centerZ, double radiusSquared) {
+ double Lx = centerX - originX;
+ double Ly = centerY - originY;
+ double Lz = centerZ - originZ;
+ double tca = Lx * dirX + Ly * dirY + Lz * dirZ;
+ double d2 = Lx * Lx + Ly * Ly + Lz * Lz - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ double thc = Math.sqrt(radiusSquared - d2);
+ double t0 = tca - thc;
+ double t1 = tca + thc;
+ return t0 < t1 && t1 >= 0.0;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and normalized direction dir
+ * intersects the sphere with the given center
and square radius.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's normalized direction
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean testRaySphere(Vector3dc origin, Vector3dc dir, Vector3dc center, double radiusSquared) {
+ return testRaySphere(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), center.x(), center.y(), center.z(), radiusSquared);
+ }
+
+ /**
+ * Test whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the given sphere with center (centerX, centerY, centerZ)
and square radius radiusSquared
.
+ *
+ * Reference: http://paulbourke.net/
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the line segment intersects the sphere; false
otherwise
+ */
+ public static boolean testLineSegmentSphere(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z,
+ double centerX, double centerY, double centerZ, double radiusSquared) {
+ double dX = p1X - p0X;
+ double dY = p1Y - p0Y;
+ double dZ = p1Z - p0Z;
+ double nom = (centerX - p0X) * dX + (centerY - p0Y) * dY + (centerZ - p0Z) * dZ;
+ double den = dX * dX + dY * dY + dZ * dZ;
+ double u = nom / den;
+ if (u < 0.0) {
+ dX = p0X - centerX;
+ dY = p0Y - centerY;
+ dZ = p0Z - centerZ;
+ } else if (u > 1.0) {
+ dX = p1X - centerX;
+ dY = p1Y - centerY;
+ dZ = p1Z - centerZ;
+ } else { // has to be >= 0 and <= 1
+ double pX = p0X + u * dX;
+ double pY = p0Y + u * dY;
+ double pZ = p0Z + u * dZ;
+ dX = pX - centerX;
+ dY = pY - centerY;
+ dZ = pZ - centerZ;
+ }
+ double dist = dX * dX + dY * dY + dZ * dZ;
+ return dist <= radiusSquared;
+ }
+
+ /**
+ * Test whether the line segment with the end points p0
and p1
+ * intersects the given sphere with center center
and square radius radiusSquared
.
+ *
+ * Reference: http://paulbourke.net/
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the line segment intersects the sphere; false
otherwise
+ */
+ public static boolean testLineSegmentSphere(Vector3dc p0, Vector3dc p1, Vector3dc center, double radiusSquared) {
+ return testLineSegmentSphere(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), center.x(), center.y(), center.z(), radiusSquared);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the axis-aligned box given as its minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)
+ * @see RayAabIntersection
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * iff the ray intersects the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean intersectRayAab(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector2d result) {
+ double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY, invDirZ = 1.0 / dirZ;
+ double tNear, tFar, tymin, tymax, tzmin, tzmax;
+ if (invDirX >= 0.0) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return false;
+ if (invDirZ >= 0.0) {
+ tzmin = (minZ - originZ) * invDirZ;
+ tzmax = (maxZ - originZ) * invDirZ;
+ } else {
+ tzmin = (maxZ - originZ) * invDirZ;
+ tzmax = (minZ - originZ) * invDirZ;
+ }
+ if (tNear > tzmax || tzmin > tFar)
+ return false;
+ tNear = tymin > tNear || Double.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Double.isNaN(tFar) ? tymax : tFar;
+ tNear = tzmin > tNear ? tzmin : tNear;
+ tFar = tzmax < tFar ? tzmax : tFar;
+ if (tNear < tFar && tFar >= 0.0) {
+ result.x = tNear;
+ result.y = tFar;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the axis-aligned box specified as its minimum corner min
and maximum corner max
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection..
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)
+ * @see RayAabIntersection
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * iff the ray intersects the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean intersectRayAab(Vector3dc origin, Vector3dc dir, Vector3dc min, Vector3dc max, Vector2d result) {
+ return intersectRayAab(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), result);
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the axis-aligned box given as its minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection.
+ *
+ * This method returns true
for a line segment whose either end point lies inside the axis-aligned box.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectLineSegmentAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param minX
+ * the x coordinate of one corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of one corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of one corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the opposite corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the opposite corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the opposite corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * iff the line segment intersects the axis-aligned box
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned box; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned box; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned box; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two sides of the axis-aligned box
+ * or lies on an edge or a side of the box
+ */
+ public static int intersectLineSegmentAab(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z,
+ double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector2d result) {
+ double dirX = p1X - p0X, dirY = p1Y - p0Y, dirZ = p1Z - p0Z;
+ double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY, invDirZ = 1.0 / dirZ;
+ double tNear, tFar, tymin, tymax, tzmin, tzmax;
+ if (invDirX >= 0.0) {
+ tNear = (minX - p0X) * invDirX;
+ tFar = (maxX - p0X) * invDirX;
+ } else {
+ tNear = (maxX - p0X) * invDirX;
+ tFar = (minX - p0X) * invDirX;
+ }
+ if (invDirY >= 0.0) {
+ tymin = (minY - p0Y) * invDirY;
+ tymax = (maxY - p0Y) * invDirY;
+ } else {
+ tymin = (maxY - p0Y) * invDirY;
+ tymax = (minY - p0Y) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return OUTSIDE;
+ if (invDirZ >= 0.0) {
+ tzmin = (minZ - p0Z) * invDirZ;
+ tzmax = (maxZ - p0Z) * invDirZ;
+ } else {
+ tzmin = (maxZ - p0Z) * invDirZ;
+ tzmax = (minZ - p0Z) * invDirZ;
+ }
+ if (tNear > tzmax || tzmin > tFar)
+ return OUTSIDE;
+ tNear = tymin > tNear || Double.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Double.isNaN(tFar) ? tymax : tFar;
+ tNear = tzmin > tNear ? tzmin : tNear;
+ tFar = tzmax < tFar ? tzmax : tFar;
+ int type = OUTSIDE;
+ if (tNear <= tFar && tNear <= 1.0f && tFar >= 0.0f) {
+ if (tNear >= 0.0f && tFar > 1.0f) {
+ tFar = tNear;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar <= 1.0f) {
+ tNear = tFar;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar > 1.0f) {
+ type = INSIDE;
+ } else {
+ type = TWO_INTERSECTION;
+ }
+ result.x = tNear;
+ result.y = tFar;
+ }
+ return type;
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points p0
and p1
+ * intersects the axis-aligned box given as its minimum corner min
and maximum corner max
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection.
+ *
+ * This method returns true
for a line segment whose either end point lies inside the axis-aligned box.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectLineSegmentAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector2d)
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * iff the line segment intersects the axis-aligned box
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned box; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned box; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned box; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two sides of the axis-aligned box
+ * or lies on an edge or a side of the box
+ */
+ public static int intersectLineSegmentAab(Vector3dc p0, Vector3dc p1, Vector3dc min, Vector3dc max, Vector2d result) {
+ return intersectLineSegmentAab(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the axis-aligned box given as its minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAab(Vector3dc, Vector3dc, Vector3dc, Vector3dc)
+ * @see RayAabIntersection
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean testRayAab(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
+ double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY, invDirZ = 1.0 / dirZ;
+ double tNear, tFar, tymin, tymax, tzmin, tzmax;
+ if (invDirX >= 0.0) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return false;
+ if (invDirZ >= 0.0) {
+ tzmin = (minZ - originZ) * invDirZ;
+ tzmax = (maxZ - originZ) * invDirZ;
+ } else {
+ tzmin = (maxZ - originZ) * invDirZ;
+ tzmax = (minZ - originZ) * invDirZ;
+ }
+ if (tNear > tzmax || tzmin > tFar)
+ return false;
+ tNear = tymin > tNear || Double.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Double.isNaN(tFar) ? tymax : tFar;
+ tNear = tzmin > tNear ? tzmin : tNear;
+ tFar = tzmax < tFar ? tzmax : tFar;
+ return tNear < tFar && tFar >= 0.0;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the axis-aligned box specified as its minimum corner min
and maximum corner max
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAab(double, double, double, double, double, double, double, double, double, double, double, double)
+ * @see RayAabIntersection
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean testRayAab(Vector3dc origin, Vector3dc dir, Vector3dc min, Vector3dc max) {
+ return testRayAab(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), min.x(), min.y(), min.z(), max.x(), max.y(), max.z());
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the frontface of the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #testRayTriangleFront(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3dc, double)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangleFront(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon) {
+ double edge1X = v1X - v0X;
+ double edge1Y = v1Y - v0Y;
+ double edge1Z = v1Z - v0Z;
+ double edge2X = v2X - v0X;
+ double edge2Y = v2Y - v0Y;
+ double edge2Z = v2Z - v0Z;
+ double pvecX = dirY * edge2Z - dirZ * edge2Y;
+ double pvecY = dirZ * edge2X - dirX * edge2Z;
+ double pvecZ = dirX * edge2Y - dirY * edge2X;
+ double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det < epsilon)
+ return false;
+ double tvecX = originX - v0X;
+ double tvecY = originY - v0Y;
+ double tvecZ = originZ - v0Z;
+ double u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ);
+ if (u < 0.0 || u > det)
+ return false;
+ double qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ double qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ double qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ double v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ);
+ if (v < 0.0 || u + v > det)
+ return false;
+ double invDet = 1.0 / det;
+ double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t >= epsilon;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and the given dir
intersects the frontface of the triangle consisting of the three vertices
+ * v0
, v1
and v2
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #testRayTriangleFront(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangleFront(Vector3dc origin, Vector3dc dir, Vector3dc v0, Vector3dc v1, Vector3dc v2, double epsilon) {
+ return testRayTriangleFront(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #testRayTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3dc, double)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangle(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon) {
+ double edge1X = v1X - v0X;
+ double edge1Y = v1Y - v0Y;
+ double edge1Z = v1Z - v0Z;
+ double edge2X = v2X - v0X;
+ double edge2Y = v2Y - v0Y;
+ double edge2Z = v2Z - v0Z;
+ double pvecX = dirY * edge2Z - dirZ * edge2Y;
+ double pvecY = dirZ * edge2X - dirX * edge2Z;
+ double pvecZ = dirX * edge2Y - dirY * edge2X;
+ double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det > -epsilon && det < epsilon)
+ return false;
+ double tvecX = originX - v0X;
+ double tvecY = originY - v0Y;
+ double tvecZ = originZ - v0Z;
+ double invDet = 1.0 / det;
+ double u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet;
+ if (u < 0.0 || u > 1.0)
+ return false;
+ double qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ double qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ double qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ double v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ) * invDet;
+ if (v < 0.0 || u + v > 1.0)
+ return false;
+ double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t >= epsilon;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and the given dir
intersects the frontface of the triangle consisting of the three vertices
+ * v0
, v1
and v2
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #testRayTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangle(Vector3dc origin, Vector3dc dir, Vector3dc v0, Vector3dc v1, Vector3dc v2, double epsilon) {
+ return testRayTriangle(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Determine whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the frontface of the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
+ * and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #testRayTriangleFront(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3dc, double)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the frontface of the triangle; -1.0
otherwise
+ */
+ public static double intersectRayTriangleFront(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon) {
+ double edge1X = v1X - v0X;
+ double edge1Y = v1Y - v0Y;
+ double edge1Z = v1Z - v0Z;
+ double edge2X = v2X - v0X;
+ double edge2Y = v2Y - v0Y;
+ double edge2Z = v2Z - v0Z;
+ double pvecX = dirY * edge2Z - dirZ * edge2Y;
+ double pvecY = dirZ * edge2X - dirX * edge2Z;
+ double pvecZ = dirX * edge2Y - dirY * edge2X;
+ double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det <= epsilon)
+ return -1.0;
+ double tvecX = originX - v0X;
+ double tvecY = originY - v0Y;
+ double tvecZ = originZ - v0Z;
+ double u = tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ;
+ if (u < 0.0 || u > det)
+ return -1.0;
+ double qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ double qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ double qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ double v = dirX * qvecX + dirY * qvecY + dirZ * qvecZ;
+ if (v < 0.0 || u + v > det)
+ return -1.0;
+ double invDet = 1.0 / det;
+ double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t;
+ }
+
+ /**
+ * Determine whether the ray with the given origin
and the given dir
intersects the frontface of the triangle consisting of the three vertices
+ * v0
, v1
and v2
and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #intersectRayTriangleFront(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the frontface of the triangle; -1.0
otherwise
+ */
+ public static double intersectRayTriangleFront(Vector3dc origin, Vector3dc dir, Vector3dc v0, Vector3dc v1, Vector3dc v2, double epsilon) {
+ return intersectRayTriangleFront(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Determine whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
+ * and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #testRayTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3dc, double)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the triangle; -1.0
otherwise
+ */
+ public static double intersectRayTriangle(double originX, double originY, double originZ, double dirX, double dirY, double dirZ,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon) {
+ double edge1X = v1X - v0X;
+ double edge1Y = v1Y - v0Y;
+ double edge1Z = v1Z - v0Z;
+ double edge2X = v2X - v0X;
+ double edge2Y = v2Y - v0Y;
+ double edge2Z = v2Z - v0Z;
+ double pvecX = dirY * edge2Z - dirZ * edge2Y;
+ double pvecY = dirZ * edge2X - dirX * edge2Z;
+ double pvecZ = dirX * edge2Y - dirY * edge2X;
+ double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det > -epsilon && det < epsilon)
+ return -1.0;
+ double tvecX = originX - v0X;
+ double tvecY = originY - v0Y;
+ double tvecZ = originZ - v0Z;
+ double invDet = 1.0 / det;
+ double u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet;
+ if (u < 0.0 || u > 1.0)
+ return -1.0;
+ double qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ double qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ double qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ double v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ) * invDet;
+ if (v < 0.0 || u + v > 1.0)
+ return -1.0;
+ double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t;
+ }
+
+ /**
+ * Determine whether the ray with the given origin
and the given dir
intersects the triangle consisting of the three vertices
+ * v0
, v1
and v2
and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #intersectRayTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the triangle; -1.0
otherwise
+ */
+ public static double intersectRayTriangle(Vector3dc origin, Vector3dc dir, Vector3dc v0, Vector3dc v1, Vector3dc v2, double epsilon) {
+ return intersectRayTriangle(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Test whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #testLineSegmentTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3dc, double)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean testLineSegmentTriangle(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon) {
+ double dirX = p1X - p0X;
+ double dirY = p1Y - p0Y;
+ double dirZ = p1Z - p0Z;
+ double t = intersectRayTriangle(p0X, p0Y, p0Z, dirX, dirY, dirZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, epsilon);
+ return t >= 0.0 && t <= 1.0;
+ }
+
+ /**
+ * Test whether the line segment with the end points p0
and p1
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #testLineSegmentTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean testLineSegmentTriangle(Vector3dc p0, Vector3dc p1, Vector3dc v0, Vector3dc v1, Vector3dc v2, double epsilon) {
+ return testLineSegmentTriangle(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Determine whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points,
+ * and return the point of intersection.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #intersectLineSegmentTriangle(Vector3dc, Vector3dc, Vector3dc, Vector3dc, Vector3dc, double, Vector3d)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @param intersectionPoint
+ * the point of intersection
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean intersectLineSegmentTriangle(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z,
+ double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z,
+ double epsilon, Vector3d intersectionPoint) {
+ double dirX = p1X - p0X;
+ double dirY = p1Y - p0Y;
+ double dirZ = p1Z - p0Z;
+ double t = intersectRayTriangle(p0X, p0Y, p0Z, dirX, dirY, dirZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, epsilon);
+ if (t >= 0.0 && t <= 1.0) {
+ intersectionPoint.x = p0X + dirX * t;
+ intersectionPoint.y = p0Y + dirY * t;
+ intersectionPoint.z = p0Z + dirZ * t;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine whether the line segment with the end points p0
and p1
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points,
+ * and return the point of intersection.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #intersectLineSegmentTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @param intersectionPoint
+ * the point of intersection
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean intersectLineSegmentTriangle(Vector3dc p0, Vector3dc p1, Vector3dc v0, Vector3dc v1, Vector3dc v2, double epsilon, Vector3d intersectionPoint) {
+ return intersectLineSegmentTriangle(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon, intersectionPoint);
+ }
+
+ /**
+ * Determine whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the plane given as the general plane equation a*x + b*y + c*z + d = 0,
+ * and return the point of intersection.
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param intersectionPoint
+ * the point of intersection
+ * @return true
if the given line segment intersects the plane; false
otherwise
+ */
+ public static boolean intersectLineSegmentPlane(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z,
+ double a, double b, double c, double d, Vector3d intersectionPoint) {
+ double dirX = p1X - p0X;
+ double dirY = p1Y - p0Y;
+ double dirZ = p1Z - p0Z;
+ double denom = a * dirX + b * dirY + c * dirZ;
+ double t = -(a * p0X + b * p0Y + c * p0Z + d) / denom;
+ if (t >= 0.0 && t <= 1.0) {
+ intersectionPoint.x = p0X + t * dirX;
+ intersectionPoint.y = p0Y + t * dirY;
+ intersectionPoint.z = p0Z + t * dirZ;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the line with the general line equation a*x + b*y + c = 0 intersects the circle with center
+ * (centerX, centerY)
and radius
.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the line equation
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radius
+ * the radius of the circle
+ * @return true
iff the line intersects the circle; false
otherwise
+ */
+ public static boolean testLineCircle(double a, double b, double c, double centerX, double centerY, double radius) {
+ double denom = Math.sqrt(a * a + b * b);
+ double dist = (a * centerX + b * centerY + c) / denom;
+ return -radius <= dist && dist <= radius;
+ }
+
+ /**
+ * Test whether the line with the general line equation a*x + b*y + c = 0 intersects the circle with center
+ * (centerX, centerY)
and radius
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the line equation
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radius
+ * the radius of the circle
+ * @param intersectionCenterAndHL
+ * will hold the center of the line segment of intersection in the (x, y)
components and the half-length in the z component
+ * @return true
iff the line intersects the circle; false
otherwise
+ */
+ public static boolean intersectLineCircle(double a, double b, double c, double centerX, double centerY, double radius, Vector3d intersectionCenterAndHL) {
+ double invDenom = Math.invsqrt(a * a + b * b);
+ double dist = (a * centerX + b * centerY + c) * invDenom;
+ if (-radius <= dist && dist <= radius) {
+ intersectionCenterAndHL.x = centerX + dist * a * invDenom;
+ intersectionCenterAndHL.y = centerY + dist * b * invDenom;
+ intersectionCenterAndHL.z = Math.sqrt(radius * radius - dist * dist);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the line defined by the two points (x0, y0)
and (x1, y1)
intersects the circle with center
+ * (centerX, centerY)
and radius
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radius
+ * the radius of the circle
+ * @param intersectionCenterAndHL
+ * will hold the center of the line segment of intersection in the (x, y)
components and the half-length in the z component
+ * @return true
iff the line intersects the circle; false
otherwise
+ */
+ public static boolean intersectLineCircle(double x0, double y0, double x1, double y1, double centerX, double centerY, double radius, Vector3d intersectionCenterAndHL) {
+ // Build general line equation from two points and use the other method
+ return intersectLineCircle(y0 - y1, x1 - x0, (x0 - x1) * y0 + (y1 - y0) * x0, centerX, centerY, radius, intersectionCenterAndHL);
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minX, minY)
and maximum corner (maxX, maxY)
+ * intersects the line with the general equation a*x + b*y + c = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the plane equation
+ * @return true
iff the axis-aligned rectangle intersects the line; false
otherwise
+ */
+ public static boolean testAarLine(double minX, double minY, double maxX, double maxY, double a, double b, double c) {
+ double pX, pY, nX, nY;
+ if (a > 0.0) {
+ pX = maxX;
+ nX = minX;
+ } else {
+ pX = minX;
+ nX = maxX;
+ }
+ if (b > 0.0) {
+ pY = maxY;
+ nY = minY;
+ } else {
+ pY = minY;
+ nY = maxY;
+ }
+ double distN = c + a * nX + b * nY;
+ double distP = c + a * pX + b * pY;
+ return distN <= 0.0 && distP >= 0.0;
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner min
and maximum corner max
+ * intersects the line with the general equation a*x + b*y + c = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the line equation
+ * @return true
iff the axis-aligned rectangle intersects the line; false
otherwise
+ */
+ public static boolean testAarLine(Vector2dc min, Vector2dc max, double a, double b, double c) {
+ return testAarLine(min.x(), min.y(), max.x(), max.y(), a, b, c);
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minX, minY)
and maximum corner (maxX, maxY)
+ * intersects the line defined by the two points (x0, y0)
and (x1, y1)
.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @return true
iff the axis-aligned rectangle intersects the line; false
otherwise
+ */
+ public static boolean testAarLine(double minX, double minY, double maxX, double maxY, double x0, double y0, double x1, double y1) {
+ double a = y0 - y1;
+ double b = x1 - x0;
+ double c = -b * y0 - a * x0;
+ return testAarLine(minX, minY, maxX, maxY, a, b, c);
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minXA, minYA)
and maximum corner (maxXA, maxYA)
+ * intersects the axis-aligned rectangle with minimum corner (minXB, minYB)
and maximum corner (maxXB, maxYB)
.
+ *
+ * @param minXA
+ * the x coordinate of the minimum corner of the first axis-aligned rectangle
+ * @param minYA
+ * the y coordinate of the minimum corner of the first axis-aligned rectangle
+ * @param maxXA
+ * the x coordinate of the maximum corner of the first axis-aligned rectangle
+ * @param maxYA
+ * the y coordinate of the maximum corner of the first axis-aligned rectangle
+ * @param minXB
+ * the x coordinate of the minimum corner of the second axis-aligned rectangle
+ * @param minYB
+ * the y coordinate of the minimum corner of the second axis-aligned rectangle
+ * @param maxXB
+ * the x coordinate of the maximum corner of the second axis-aligned rectangle
+ * @param maxYB
+ * the y coordinate of the maximum corner of the second axis-aligned rectangle
+ * @return true
iff both axis-aligned rectangles intersect; false
otherwise
+ */
+ public static boolean testAarAar(double minXA, double minYA, double maxXA, double maxYA, double minXB, double minYB, double maxXB, double maxYB) {
+ return maxXA >= minXB && maxYA >= minYB && minXA <= maxXB && minYA <= maxYB;
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner minA
and maximum corner maxA
+ * intersects the axis-aligned rectangle with minimum corner minB
and maximum corner maxB
.
+ *
+ * @param minA
+ * the minimum corner of the first axis-aligned rectangle
+ * @param maxA
+ * the maximum corner of the first axis-aligned rectangle
+ * @param minB
+ * the minimum corner of the second axis-aligned rectangle
+ * @param maxB
+ * the maximum corner of the second axis-aligned rectangle
+ * @return true
iff both axis-aligned rectangles intersect; false
otherwise
+ */
+ public static boolean testAarAar(Vector2dc minA, Vector2dc maxA, Vector2dc minB, Vector2dc maxB) {
+ return testAarAar(minA.x(), minA.y(), maxA.x(), maxA.y(), minB.x(), minB.y(), maxB.x(), maxB.y());
+ }
+
+ /**
+ * Test whether a given circle with center (aX, aY)
and radius aR
and travelled distance vector (maX, maY)
+ * intersects a given static circle with center (bX, bY)
and radius bR
.
+ *
+ * Note that the case of two moving circles can always be reduced to this case by expressing the moved distance of one of the circles relative
+ * to the other.
+ *
+ * Reference: https://www.gamasutra.com
+ *
+ * @param aX
+ * the x coordinate of the first circle's center
+ * @param aY
+ * the y coordinate of the first circle's center
+ * @param maX
+ * the x coordinate of the first circle's travelled distance vector
+ * @param maY
+ * the y coordinate of the first circle's travelled distance vector
+ * @param aR
+ * the radius of the first circle
+ * @param bX
+ * the x coordinate of the second circle's center
+ * @param bY
+ * the y coordinate of the second circle's center
+ * @param bR
+ * the radius of the second circle
+ * @return true
if both circle intersect; false
otherwise
+ */
+ public static boolean testMovingCircleCircle(double aX, double aY, double maX, double maY, double aR, double bX, double bY, double bR) {
+ double aRbR = aR + bR;
+ double dist = Math.sqrt((aX - bX) * (aX - bX) + (aY - bY) * (aY - bY)) - aRbR;
+ double mLen = Math.sqrt(maX * maX + maY * maY);
+ if (mLen < dist)
+ return false;
+ double invMLen = 1.0 / mLen;
+ double nX = maX * invMLen;
+ double nY = maY * invMLen;
+ double cX = bX - aX;
+ double cY = bY - aY;
+ double nDotC = nX * cX + nY * cY;
+ if (nDotC <= 0.0)
+ return false;
+ double cLen = Math.sqrt(cX * cX + cY * cY);
+ double cLenNdotC = cLen * cLen - nDotC * nDotC;
+ double aRbR2 = aRbR * aRbR;
+ if (cLenNdotC >= aRbR2)
+ return false;
+ double t = aRbR2 - cLenNdotC;
+ if (t < 0.0)
+ return false;
+ double distance = nDotC - Math.sqrt(t);
+ double mag = mLen;
+ if (mag < distance)
+ return false;
+ return true;
+ }
+
+ /**
+ * Test whether a given circle with center centerA
and radius aR
and travelled distance vector moveA
+ * intersects a given static circle with center centerB
and radius bR
.
+ *
+ * Note that the case of two moving circles can always be reduced to this case by expressing the moved distance of one of the circles relative
+ * to the other.
+ *
+ * Reference: https://www.gamasutra.com
+ *
+ * @param centerA
+ * the coordinates of the first circle's center
+ * @param moveA
+ * the coordinates of the first circle's travelled distance vector
+ * @param aR
+ * the radius of the first circle
+ * @param centerB
+ * the coordinates of the second circle's center
+ * @param bR
+ * the radius of the second circle
+ * @return true
if both circle intersect; false
otherwise
+ */
+ public static boolean testMovingCircleCircle(Vector2d centerA, Vector2d moveA, double aR, Vector2d centerB, double bR) {
+ return testMovingCircleCircle(centerA.x, centerA.y, moveA.x, moveA.y, aR, centerB.x, centerB.y, bR);
+ }
+
+ /**
+ * Test whether the one circle with center (aX, aY)
and square radius radiusSquaredA
intersects the other
+ * circle with center (bX, bY)
and square radius radiusSquaredB
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * This method returns false
when one circle contains the other circle.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param aX
+ * the x coordinate of the first circle's center
+ * @param aY
+ * the y coordinate of the first circle's center
+ * @param radiusSquaredA
+ * the square of the first circle's radius
+ * @param bX
+ * the x coordinate of the second circle's center
+ * @param bY
+ * the y coordinate of the second circle's center
+ * @param radiusSquaredB
+ * the square of the second circle's radius
+ * @param intersectionCenterAndHL
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean intersectCircleCircle(double aX, double aY, double radiusSquaredA, double bX, double bY, double radiusSquaredB, Vector3d intersectionCenterAndHL) {
+ double dX = bX - aX, dY = bY - aY;
+ double distSquared = dX * dX + dY * dY;
+ double h = 0.5 + (radiusSquaredA - radiusSquaredB) / distSquared;
+ double r_i = Math.sqrt(radiusSquaredA - h * h * distSquared);
+ if (r_i >= 0.0) {
+ intersectionCenterAndHL.x = aX + h * dX;
+ intersectionCenterAndHL.y = aY + h * dY;
+ intersectionCenterAndHL.z = r_i;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the one circle with center centerA
and square radius radiusSquaredA
intersects the other
+ * circle with center centerB
and square radius radiusSquaredB
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * This method returns false
when one circle contains the other circle.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first circle's center
+ * @param radiusSquaredA
+ * the square of the first circle's radius
+ * @param centerB
+ * the second circle's center
+ * @param radiusSquaredB
+ * the square of the second circle's radius
+ * @param intersectionCenterAndHL
+ * will hold the center of the line segment of intersection in the (x, y)
components and the half-length in the z component
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean intersectCircleCircle(Vector2dc centerA, double radiusSquaredA, Vector2dc centerB, double radiusSquaredB, Vector3d intersectionCenterAndHL) {
+ return intersectCircleCircle(centerA.x(), centerA.y(), radiusSquaredA, centerB.x(), centerB.y(), radiusSquaredB, intersectionCenterAndHL);
+ }
+
+ /**
+ * Test whether the one circle with center (aX, aY)
and radius rA
intersects the other circle with center (bX, bY)
and radius rB
.
+ *
+ * This method returns true
when one circle contains the other circle.
+ *
+ * Reference: http://math.stackexchange.com/
+ *
+ * @param aX
+ * the x coordinate of the first circle's center
+ * @param aY
+ * the y coordinate of the first circle's center
+ * @param rA
+ * the square of the first circle's radius
+ * @param bX
+ * the x coordinate of the second circle's center
+ * @param bY
+ * the y coordinate of the second circle's center
+ * @param rB
+ * the square of the second circle's radius
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean testCircleCircle(double aX, double aY, double rA, double bX, double bY, double rB) {
+ double d = (aX - bX) * (aX - bX) + (aY - bY) * (aY - bY);
+ return d <= (rA + rB) * (rA + rB);
+ }
+
+ /**
+ * Test whether the one circle with center centerA
and square radius radiusSquaredA
intersects the other
+ * circle with center centerB
and square radius radiusSquaredB
.
+ *
+ * This method returns true
when one circle contains the other circle.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first circle's center
+ * @param radiusSquaredA
+ * the square of the first circle's radius
+ * @param centerB
+ * the second circle's center
+ * @param radiusSquaredB
+ * the square of the second circle's radius
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean testCircleCircle(Vector2dc centerA, double radiusSquaredA, Vector2dc centerB, double radiusSquaredB) {
+ return testCircleCircle(centerA.x(), centerA.y(), radiusSquaredA, centerB.x(), centerB.y(), radiusSquaredB);
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY)
to the line specified via its general plane equation
+ * a*x + b*y + c = 0.
+ *
+ * Reference: http://mathworld.wolfram.com
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the constant in the plane equation
+ * @return the distance between the point and the line
+ */
+ public static double distancePointLine(double pointX, double pointY, double a, double b, double c) {
+ double denom = Math.sqrt(a * a + b * b);
+ return (a * pointX + b * pointY + c) / denom;
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY)
to the line defined by the two points (x0, y0)
and (x1, y1)
.
+ *
+ * Reference: http://mathworld.wolfram.com
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @return the distance between the point and the line
+ */
+ public static double distancePointLine(double pointX, double pointY, double x0, double y0, double x1, double y1) {
+ double dx = x1 - x0;
+ double dy = y1 - y0;
+ double denom = Math.sqrt(dx * dx + dy * dy);
+ return (dx * (y0 - pointY) - (x0 - pointX) * dy) / denom;
+ }
+
+ /**
+ * Compute the distance of the given point (pX, pY, pZ)
to the line defined by the two points (x0, y0, z0)
and (x1, y1, z1)
.
+ *
+ * Reference: http://mathworld.wolfram.com
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param z0
+ * the z coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @param z1
+ * the z coordinate of the second point on the line
+ * @return the distance between the point and the line
+ */
+ public static double distancePointLine(double pX, double pY, double pZ,
+ double x0, double y0, double z0, double x1, double y1, double z1) {
+ double d21x = x1 - x0, d21y = y1 - y0, d21z = z1 - z0;
+ double d10x = x0 - pX, d10y = y0 - pY, d10z = z0 - pZ;
+ double cx = d21y * d10z - d21z * d10y, cy = d21z * d10x - d21x * d10z, cz = d21x * d10y - d21y * d10x;
+ return Math.sqrt((cx*cx + cy*cy + cz*cz) / (d21x*d21x + d21y*d21y + d21z*d21z));
+ }
+
+ /**
+ * Test whether the ray with given origin (originX, originY)
and direction (dirX, dirY)
intersects the line
+ * containing the given point (pointX, pointY)
and having the normal (normalX, normalY)
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the line, because it is either parallel to the line or its direction points
+ * away from the line or the ray's origin is on the negative side of the line (i.e. the line's normal points away from the ray's origin).
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param pointX
+ * the x coordinate of a point on the line
+ * @param pointY
+ * the y coordinate of a point on the line
+ * @param normalX
+ * the x coordinate of the line's normal
+ * @param normalY
+ * the y coordinate of the line's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the line
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line; -1.0
otherwise
+ */
+ public static double intersectRayLine(double originX, double originY, double dirX, double dirY, double pointX, double pointY, double normalX, double normalY, double epsilon) {
+ double denom = normalX * dirX + normalY * dirY;
+ if (denom < epsilon) {
+ double t = ((pointX - originX) * normalX + (pointY - originY) * normalY) / denom;
+ if (t >= 0.0)
+ return t;
+ }
+ return -1.0;
+ }
+
+ /**
+ * Test whether the ray with given origin
and direction dir
intersects the line
+ * containing the given point
and having the given normal
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the line, because it is either parallel to the line or its direction points
+ * away from the line or the ray's origin is on the negative side of the line (i.e. the line's normal points away from the ray's origin).
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param point
+ * a point on the line
+ * @param normal
+ * the line's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the line
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line; -1.0
otherwise
+ */
+ public static double intersectRayLine(Vector2dc origin, Vector2dc dir, Vector2dc point, Vector2dc normal, double epsilon) {
+ return intersectRayLine(origin.x(), origin.y(), dir.x(), dir.y(), point.x(), point.y(), normal.x(), normal.y(), epsilon);
+ }
+
+ /**
+ * Determine whether the ray with given origin (originX, originY)
and direction (dirX, dirY)
intersects the undirected line segment
+ * given by the two end points (aX, bY)
and (bX, bY)
, and return the value of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the intersection point, if any.
+ *
+ * This method returns -1.0
if the ray does not intersect the line segment.
+ *
+ * @see #intersectRayLineSegment(Vector2dc, Vector2dc, Vector2dc, Vector2dc)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param aX
+ * the x coordinate of the line segment's first end point
+ * @param aY
+ * the y coordinate of the line segment's first end point
+ * @param bX
+ * the x coordinate of the line segment's second end point
+ * @param bY
+ * the y coordinate of the line segment's second end point
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line segment; -1.0
otherwise
+ */
+ public static double intersectRayLineSegment(double originX, double originY, double dirX, double dirY, double aX, double aY, double bX, double bY) {
+ double v1X = originX - aX;
+ double v1Y = originY - aY;
+ double v2X = bX - aX;
+ double v2Y = bY - aY;
+ double invV23 = 1.0 / (v2Y * dirX - v2X * dirY);
+ double t1 = (v2X * v1Y - v2Y * v1X) * invV23;
+ double t2 = (v1Y * dirX - v1X * dirY) * invV23;
+ if (t1 >= 0.0 && t2 >= 0.0 && t2 <= 1.0)
+ return t1;
+ return -1.0;
+ }
+
+ /**
+ * Determine whether the ray with given origin
and direction dir
intersects the undirected line segment
+ * given by the two end points a
and b
, and return the value of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the intersection point, if any.
+ *
+ * This method returns -1.0
if the ray does not intersect the line segment.
+ *
+ * @see #intersectRayLineSegment(double, double, double, double, double, double, double, double)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param a
+ * the line segment's first end point
+ * @param b
+ * the line segment's second end point
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line segment; -1.0
otherwise
+ */
+ public static double intersectRayLineSegment(Vector2dc origin, Vector2dc dir, Vector2dc a, Vector2dc b) {
+ return intersectRayLineSegment(origin.x(), origin.y(), dir.x(), dir.y(), a.x(), a.y(), b.x(), b.y());
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minX, minY)
and maximum corner (maxX, maxY)
+ * intersects the circle with the given center (centerX, centerY)
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the square of the circle's radius
+ * @return true
iff the axis-aligned rectangle intersects the circle; false
otherwise
+ */
+ public static boolean testAarCircle(double minX, double minY, double maxX, double maxY, double centerX, double centerY, double radiusSquared) {
+ double radius2 = radiusSquared;
+ if (centerX < minX) {
+ double d = (centerX - minX);
+ radius2 -= d * d;
+ } else if (centerX > maxX) {
+ double d = (centerX - maxX);
+ radius2 -= d * d;
+ }
+ if (centerY < minY) {
+ double d = (centerY - minY);
+ radius2 -= d * d;
+ } else if (centerY > maxY) {
+ double d = (centerY - maxY);
+ radius2 -= d * d;
+ }
+ return radius2 >= 0.0;
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner min
and maximum corner max
+ * intersects the circle with the given center
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the squared of the circle's radius
+ * @return true
iff the axis-aligned rectangle intersects the circle; false
otherwise
+ */
+ public static boolean testAarCircle(Vector2dc min, Vector2dc max, Vector2dc center, double radiusSquared) {
+ return testAarCircle(min.x(), min.y(), max.x(), max.y(), center.x(), center.y(), radiusSquared);
+ }
+
+ /**
+ * Determine the closest point on the triangle with the given vertices (v0X, v0Y)
, (v1X, v1Y)
, (v2X, v2Y)
+ * between that triangle and the given point (pX, pY)
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y, double pX, double pY, Vector2d result) {
+ double abX = v1X - v0X, abY = v1Y - v0Y;
+ double acX = v2X - v0X, acY = v2Y - v0Y;
+ double apX = pX - v0X, apY = pY - v0Y;
+ double d1 = abX * apX + abY * apY;
+ double d2 = acX * apX + acY * apY;
+ if (d1 <= 0.0 && d2 <= 0.0) {
+ result.x = v0X;
+ result.y = v0Y;
+ return POINT_ON_TRIANGLE_VERTEX_0;
+ }
+ double bpX = pX - v1X, bpY = pY - v1Y;
+ double d3 = abX * bpX + abY * bpY;
+ double d4 = acX * bpX + acY * bpY;
+ if (d3 >= 0.0 && d4 <= d3) {
+ result.x = v1X;
+ result.y = v1Y;
+ return POINT_ON_TRIANGLE_VERTEX_1;
+ }
+ double vc = d1 * d4 - d3 * d2;
+ if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) {
+ double v = d1 / (d1 - d3);
+ result.x = v0X + v * abX;
+ result.y = v0Y + v * abY;
+ return POINT_ON_TRIANGLE_EDGE_01;
+ }
+ double cpX = pX - v2X, cpY = pY - v2Y;
+ double d5 = abX * cpX + abY * cpY;
+ double d6 = acX * cpX + acY * cpY;
+ if (d6 >= 0.0 && d5 <= d6) {
+ result.x = v2X;
+ result.y = v2Y;
+ return POINT_ON_TRIANGLE_VERTEX_2;
+ }
+ double vb = d5 * d2 - d1 * d6;
+ if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) {
+ double w = d2 / (d2 - d6);
+ result.x = v0X + w * acX;
+ result.y = v0Y + w * acY;
+ return POINT_ON_TRIANGLE_EDGE_20;
+ }
+ double va = d3 * d6 - d5 * d4;
+ if (va <= 0.0 && d4 - d3 >= 0.0 && d5 - d6 >= 0.0) {
+ double w = (d4 - d3) / (d4 - d3 + d5 - d6);
+ result.x = v1X + w * (v2X - v1X);
+ result.y = v1Y + w * (v2Y - v1Y);
+ return POINT_ON_TRIANGLE_EDGE_12;
+ }
+ double denom = 1.0 / (va + vb + vc);
+ double v = vb * denom;
+ double w = vc * denom;
+ result.x = v0X + abX * v + acX * w;
+ result.y = v0Y + abY * v + acY * w;
+ return POINT_ON_TRIANGLE_FACE;
+ }
+
+ /**
+ * Determine the closest point on the triangle with the vertices v0
, v1
, v2
+ * between that triangle and the given point p
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @param p
+ * the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(Vector2dc v0, Vector2dc v1, Vector2dc v2, Vector2dc p, Vector2d result) {
+ return findClosestPointOnTriangle(v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y(), p.x(), p.y(), result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the given circle with center (centerX, centerY)
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the circle
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean intersectRayCircle(double originX, double originY, double dirX, double dirY,
+ double centerX, double centerY, double radiusSquared, Vector2d result) {
+ double Lx = centerX - originX;
+ double Ly = centerY - originY;
+ double tca = Lx * dirX + Ly * dirY;
+ double d2 = Lx * Lx + Ly * Ly - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ double thc = Math.sqrt(radiusSquared - d2);
+ double t0 = tca - thc;
+ double t1 = tca + thc;
+ if (t0 < t1 && t1 >= 0.0) {
+ result.x = t0;
+ result.y = t1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the circle with the given center
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the circle
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean intersectRayCircle(Vector2dc origin, Vector2dc dir, Vector2dc center, double radiusSquared, Vector2d result) {
+ return intersectRayCircle(origin.x(), origin.y(), dir.x(), dir.y(), center.x(), center.y(), radiusSquared, result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the given circle with center (centerX, centerY)
and square radius radiusSquared
.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean testRayCircle(double originX, double originY, double dirX, double dirY,
+ double centerX, double centerY, double radiusSquared) {
+ double Lx = centerX - originX;
+ double Ly = centerY - originY;
+ double tca = Lx * dirX + Ly * dirY;
+ double d2 = Lx * Lx + Ly * Ly - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ double thc = Math.sqrt(radiusSquared - d2);
+ double t0 = tca - thc;
+ double t1 = tca + thc;
+ return t0 < t1 && t1 >= 0.0;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the circle with the given center
and square radius.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean testRayCircle(Vector2dc origin, Vector2dc dir, Vector2dc center, double radiusSquared) {
+ return testRayCircle(origin.x(), origin.y(), dir.x(), dir.y(), center.x(), center.y(), radiusSquared);
+ }
+
+ /**
+ * Determine whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the axis-aligned rectangle given as its minimum corner (minX, minY)
and maximum corner (maxX, maxY)
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * as well as the side of the axis-aligned rectangle the ray intersects.
+ *
+ * This method also detects an intersection for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the near and far point of intersection
+ * @return the side on which the near intersection occurred as one of
+ * {@link #AAR_SIDE_MINX}, {@link #AAR_SIDE_MINY}, {@link #AAR_SIDE_MAXX} or {@link #AAR_SIDE_MAXY};
+ * or -1
if the ray does not intersect the axis-aligned rectangle;
+ */
+ public static int intersectRayAar(double originX, double originY, double dirX, double dirY,
+ double minX, double minY, double maxX, double maxY, Vector2d result) {
+ double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY;
+ double tNear, tFar, tymin, tymax;
+ if (invDirX >= 0.0) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return OUTSIDE;
+ tNear = tymin > tNear || Double.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Double.isNaN(tFar) ? tymax : tFar;
+ int side = -1; // no intersection side
+ if (tNear < tFar && tFar >= 0.0) {
+ double px = originX + tNear * dirX;
+ double py = originY + tNear * dirY;
+ result.x = tNear;
+ result.y = tFar;
+ double daX = Math.abs(px - minX);
+ double daY = Math.abs(py - minY);
+ double dbX = Math.abs(px - maxX);
+ double dbY = Math.abs(py - maxY);
+ side = 0; // min x coordinate
+ double min = daX;
+ if (daY < min) {
+ min = daY;
+ side = 1; // min y coordinate
+ }
+ if (dbX < min) {
+ min = dbX;
+ side = 2; // max xcoordinate
+ }
+ if (dbY < min)
+ side = 3; // max y coordinate
+ }
+ return side;
+ }
+
+ /**
+ * Determine whether the given ray with the given origin
and direction dir
+ * intersects the axis-aligned rectangle given as its minimum corner min
and maximum corner max
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * as well as the side of the axis-aligned rectangle the ray intersects.
+ *
+ * This method also detects an intersection for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the near and far point of intersection
+ * @return the side on which the near intersection occurred as one of
+ * {@link #AAR_SIDE_MINX}, {@link #AAR_SIDE_MINY}, {@link #AAR_SIDE_MAXX} or {@link #AAR_SIDE_MAXY};
+ * or -1
if the ray does not intersect the axis-aligned rectangle;
+ */
+ public static int intersectRayAar(Vector2dc origin, Vector2dc dir, Vector2dc min, Vector2dc max, Vector2d result) {
+ return intersectRayAar(origin.x(), origin.y(), dir.x(), dir.y(), min.x(), min.y(), max.x(), max.y(), result);
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points (p0X, p0Y)
and (p1X, p1Y)
+ * intersects the axis-aligned rectangle given as its minimum corner (minX, minY)
and maximum corner (maxX, maxY)
,
+ * and store the values of the parameter t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * into result
.
+ *
+ * This method also detects an intersection of a line segment whose either end point lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectLineSegmentAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc, Vector2d)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned rectangle; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned rectangle; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned rectangle; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two edges of the axis-aligned rectangle or lies on one edge of the rectangle
+ */
+ public static int intersectLineSegmentAar(double p0X, double p0Y, double p1X, double p1Y,
+ double minX, double minY, double maxX, double maxY, Vector2d result) {
+ double dirX = p1X - p0X, dirY = p1Y - p0Y;
+ double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY;
+ double tNear, tFar, tymin, tymax;
+ if (invDirX >= 0.0) {
+ tNear = (minX - p0X) * invDirX;
+ tFar = (maxX - p0X) * invDirX;
+ } else {
+ tNear = (maxX - p0X) * invDirX;
+ tFar = (minX - p0X) * invDirX;
+ }
+ if (invDirY >= 0.0) {
+ tymin = (minY - p0Y) * invDirY;
+ tymax = (maxY - p0Y) * invDirY;
+ } else {
+ tymin = (maxY - p0Y) * invDirY;
+ tymax = (minY - p0Y) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return OUTSIDE;
+ tNear = tymin > tNear || Double.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Double.isNaN(tFar) ? tymax : tFar;
+ int type = OUTSIDE;
+ if (tNear <= tFar && tNear <= 1.0f && tFar >= 0.0f) {
+ if (tNear >= 0.0f && tFar > 1.0f) {
+ tFar = tNear;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar <= 1.0f) {
+ tNear = tFar;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar > 1.0f) {
+ type = INSIDE;
+ } else {
+ type = TWO_INTERSECTION;
+ }
+ result.x = tNear;
+ result.y = tFar;
+ }
+ return type;
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points p0
and p1
+ * intersects the axis-aligned rectangle given as its minimum corner min
and maximum corner max
,
+ * and store the values of the parameter t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * into result
.
+ *
+ * This method also detects an intersection of a line segment whose either end point lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * #see {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)}
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned rectangle; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned rectangle; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned rectangle; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two edges of the axis-aligned rectangle
+ */
+ public static int intersectLineSegmentAar(Vector2dc p0, Vector2dc p1, Vector2dc min, Vector2dc max, Vector2d result) {
+ return intersectLineSegmentAar(p0.x(), p0.y(), p1.x(), p1.y(), min.x(), min.y(), max.x(), max.y(), result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the given axis-aligned rectangle given as its minimum corner (minX, minY)
and maximum corner (maxX, maxY)
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAar(Vector2dc, Vector2dc, Vector2dc, Vector2dc)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @return true
if the given ray intersects the axis-aligned rectangle; false
otherwise
+ */
+ public static boolean testRayAar(double originX, double originY, double dirX, double dirY, double minX, double minY, double maxX, double maxY) {
+ double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY;
+ double tNear, tFar, tymin, tymax;
+ if (invDirX >= 0.0) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return false;
+ tNear = tymin > tNear || Double.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Double.isNaN(tFar) ? tymax : tFar;
+ return tNear < tFar && tFar >= 0.0;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the given axis-aligned rectangle specified as its minimum corner min
and maximum corner max
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAar(double, double, double, double, double, double, double, double)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @return true
if the given ray intersects the axis-aligned rectangle; false
otherwise
+ */
+ public static boolean testRayAar(Vector2dc origin, Vector2dc dir, Vector2dc min, Vector2dc max) {
+ return testRayAar(origin.x(), origin.y(), dir.x(), dir.y(), min.x(), min.y(), max.x(), max.y());
+ }
+
+ /**
+ * Test whether the given point (pX, pY)
lies inside the triangle with the vertices (v0X, v0Y)
, (v1X, v1Y)
, (v2X, v2Y)
.
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @return true
iff the point lies inside the triangle; false
otherwise
+ */
+ public static boolean testPointTriangle(double pX, double pY, double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y) {
+ boolean b1 = (pX - v1X) * (v0Y - v1Y) - (v0X - v1X) * (pY - v1Y) < 0.0;
+ boolean b2 = (pX - v2X) * (v1Y - v2Y) - (v1X - v2X) * (pY - v2Y) < 0.0;
+ if (b1 != b2)
+ return false;
+ boolean b3 = (pX - v0X) * (v2Y - v0Y) - (v2X - v0X) * (pY - v0Y) < 0.0;
+ return b2 == b3;
+ }
+
+ /**
+ * Test whether the given point
lies inside the triangle with the vertices v0
, v1
, v2
.
+ *
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @param point
+ * the point
+ * @return true
iff the point lies inside the triangle; false
otherwise
+ */
+ public static boolean testPointTriangle(Vector2dc point, Vector2dc v0, Vector2dc v1, Vector2dc v2) {
+ return testPointTriangle(point.x(), point.y(), v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y());
+ }
+
+ /**
+ * Test whether the given point (pX, pY)
lies inside the axis-aligned rectangle with the minimum corner (minX, minY)
+ * and maximum corner (maxX, maxY)
.
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @return true
iff the point lies inside the axis-aligned rectangle; false
otherwise
+ */
+ public static boolean testPointAar(double pX, double pY, double minX, double minY, double maxX, double maxY) {
+ return pX >= minX && pY >= minY && pX <= maxX && pY <= maxY;
+ }
+
+ /**
+ * Test whether the point (pX, pY)
lies inside the circle with center (centerX, centerY)
and square radius radiusSquared
.
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the square radius of the circle
+ * @return true
iff the point lies inside the circle; false
otherwise
+ */
+ public static boolean testPointCircle(double pX, double pY, double centerX, double centerY, double radiusSquared) {
+ double dx = pX - centerX;
+ double dy = pY - centerY;
+ double dx2 = dx * dx;
+ double dy2 = dy * dy;
+ return dx2 + dy2 <= radiusSquared;
+ }
+
+ /**
+ * Test whether the circle with center (centerX, centerY)
and square radius radiusSquared
intersects the triangle with counter-clockwise vertices
+ * (v0X, v0Y)
, (v1X, v1Y)
, (v2X, v2Y)
.
+ *
+ * The vertices of the triangle must be specified in counter-clockwise order.
+ *
+ * Reference: http://www.phatcode.net/
+ *
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the square radius of the circle
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @return true
iff the circle intersects the triangle; false
otherwise
+ */
+ public static boolean testCircleTriangle(double centerX, double centerY, double radiusSquared, double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y) {
+ double c1x = centerX - v0X, c1y = centerY - v0Y;
+ double c1sqr = c1x * c1x + c1y * c1y - radiusSquared;
+ if (c1sqr <= 0.0)
+ return true;
+ double c2x = centerX - v1X, c2y = centerY - v1Y;
+ double c2sqr = c2x * c2x + c2y * c2y - radiusSquared;
+ if (c2sqr <= 0.0)
+ return true;
+ double c3x = centerX - v2X, c3y = centerY - v2Y;
+ double c3sqr = c3x * c3x + c3y * c3y - radiusSquared;
+ if (c3sqr <= 0.0)
+ return true;
+ double e1x = v1X - v0X, e1y = v1Y - v0Y;
+ double e2x = v2X - v1X, e2y = v2Y - v1Y;
+ double e3x = v0X - v2X, e3y = v0Y - v2Y;
+ if (e1x * c1y - e1y * c1x >= 0.0 && e2x * c2y - e2y * c2x >= 0.0 && e3x * c3y - e3y * c3x >= 0.0)
+ return true;
+ double k = c1x * e1x + c1y * e1y;
+ if (k >= 0.0) {
+ double len = e1x * e1x + e1y * e1y;
+ if (k <= len) {
+ if (c1sqr * len <= k * k)
+ return true;
+ }
+ }
+ k = c2x * e2x + c2y * e2y;
+ if (k > 0.0) {
+ double len = e2x * e2x + e2y * e2y;
+ if (k <= len) {
+ if (c2sqr * len <= k * k)
+ return true;
+ }
+ }
+ k = c3x * e3x + c3y * e3y;
+ if (k >= 0.0) {
+ double len = e3x * e3x + e3y * e3y;
+ if (k < len) {
+ if (c3sqr * len <= k * k)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the circle with given center
and square radius radiusSquared
intersects the triangle with counter-clockwise vertices
+ * v0
, v1
, v2
.
+ *
+ * The vertices of the triangle must be specified in counter-clockwise order.
+ *
+ * Reference: http://www.phatcode.net/
+ *
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the square radius of the circle
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @return true
iff the circle intersects the triangle; false
otherwise
+ */
+ public static boolean testCircleTriangle(Vector2dc center, double radiusSquared, Vector2dc v0, Vector2dc v1, Vector2dc v2) {
+ return testCircleTriangle(center.x(), center.y(), radiusSquared, v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y());
+ }
+
+ /**
+ * Determine whether the polygon specified by the given sequence of (x, y)
coordinate pairs intersects with the ray
+ * with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
, and store the point of intersection
+ * into the given vector p
.
+ *
+ * If the polygon intersects the ray, this method returns the index of the polygon edge intersecting the ray, that is, the index of the
+ * first vertex of the directed line segment. The second vertex is always that index + 1, modulus the number of polygon vertices.
+ *
+ * @param verticesXY
+ * the sequence of (x, y)
coordinate pairs of all vertices of the polygon
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param p
+ * will hold the point of intersection
+ * @return the index of the first vertex of the polygon edge that intersects the ray; or -1
if the ray does not intersect the polygon
+ */
+ public static int intersectPolygonRay(double[] verticesXY, double originX, double originY, double dirX, double dirY, Vector2d p) {
+ double nearestT = Double.POSITIVE_INFINITY;
+ int count = verticesXY.length >> 1;
+ int edgeIndex = -1;
+ double aX = verticesXY[(count-1)<<1], aY = verticesXY[((count-1)<<1) + 1];
+ for (int i = 0; i < count; i++) {
+ double bX = verticesXY[i << 1], bY = verticesXY[(i << 1) + 1];
+ double doaX = originX - aX, doaY = originY - aY;
+ double dbaX = bX - aX, dbaY = bY - aY;
+ double invDbaDir = 1.0 / (dbaY * dirX - dbaX * dirY);
+ double t = (dbaX * doaY - dbaY * doaX) * invDbaDir;
+ if (t >= 0.0 && t < nearestT) {
+ double t2 = (doaY * dirX - doaX * dirY) * invDbaDir;
+ if (t2 >= 0.0 && t2 <= 1.0) {
+ edgeIndex = (i - 1 + count) % count;
+ nearestT = t;
+ p.x = originX + t * dirX;
+ p.y = originY + t * dirY;
+ }
+ }
+ aX = bX;
+ aY = bY;
+ }
+ return edgeIndex;
+ }
+
+ /**
+ * Determine whether the polygon specified by the given sequence of vertices
intersects with the ray
+ * with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
, and store the point of intersection
+ * into the given vector p
.
+ *
+ * If the polygon intersects the ray, this method returns the index of the polygon edge intersecting the ray, that is, the index of the
+ * first vertex of the directed line segment. The second vertex is always that index + 1, modulus the number of polygon vertices.
+ *
+ * @param vertices
+ * the sequence of (x, y)
coordinate pairs of all vertices of the polygon
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param p
+ * will hold the point of intersection
+ * @return the index of the first vertex of the polygon edge that intersects the ray; or -1
if the ray does not intersect the polygon
+ */
+ public static int intersectPolygonRay(Vector2dc[] vertices, double originX, double originY, double dirX, double dirY, Vector2d p) {
+ double nearestT = Double.POSITIVE_INFINITY;
+ int count = vertices.length;
+ int edgeIndex = -1;
+ double aX = vertices[count-1].x(), aY = vertices[count-1].y();
+ for (int i = 0; i < count; i++) {
+ Vector2dc b = vertices[i];
+ double bX = b.x(), bY = b.y();
+ double doaX = originX - aX, doaY = originY - aY;
+ double dbaX = bX - aX, dbaY = bY - aY;
+ double invDbaDir = 1.0 / (dbaY * dirX - dbaX * dirY);
+ double t = (dbaX * doaY - dbaY * doaX) * invDbaDir;
+ if (t >= 0.0 && t < nearestT) {
+ double t2 = (doaY * dirX - doaX * dirY) * invDbaDir;
+ if (t2 >= 0.0 && t2 <= 1.0) {
+ edgeIndex = (i - 1 + count) % count;
+ nearestT = t;
+ p.x = originX + t * dirX;
+ p.y = originY + t * dirY;
+ }
+ }
+ aX = bX;
+ aY = bY;
+ }
+ return edgeIndex;
+ }
+
+ /**
+ * Determine whether the two lines, specified via two points lying on each line, intersect each other, and store the point of intersection
+ * into the given vector p
.
+ *
+ * @param ps1x
+ * the x coordinate of the first point on the first line
+ * @param ps1y
+ * the y coordinate of the first point on the first line
+ * @param pe1x
+ * the x coordinate of the second point on the first line
+ * @param pe1y
+ * the y coordinate of the second point on the first line
+ * @param ps2x
+ * the x coordinate of the first point on the second line
+ * @param ps2y
+ * the y coordinate of the first point on the second line
+ * @param pe2x
+ * the x coordinate of the second point on the second line
+ * @param pe2y
+ * the y coordinate of the second point on the second line
+ * @param p
+ * will hold the point of intersection
+ * @return true
iff the two lines intersect; false
otherwise
+ */
+ public static boolean intersectLineLine(double ps1x, double ps1y, double pe1x, double pe1y, double ps2x, double ps2y, double pe2x, double pe2y, Vector2d p) {
+ double d1x = ps1x - pe1x;
+ double d1y = pe1y - ps1y;
+ double d1ps1 = d1y * ps1x + d1x * ps1y;
+ double d2x = ps2x - pe2x;
+ double d2y = pe2y - ps2y;
+ double d2ps2 = d2y * ps2x + d2x * ps2y;
+ double det = d1y * d2x - d2y * d1x;
+ if (det == 0.0)
+ return false;
+ p.x = (d2x * d1ps1 - d1x * d2ps2) / det;
+ p.y = (d1y * d2ps2 - d2y * d1ps1) / det;
+ return true;
+ }
+
+ private static boolean separatingAxis(Vector2d[] v1s, Vector2d[] v2s, double aX, double aY) {
+ double minA = Double.POSITIVE_INFINITY, maxA = Double.NEGATIVE_INFINITY;
+ double minB = Double.POSITIVE_INFINITY, maxB = Double.NEGATIVE_INFINITY;
+ int maxLen = Math.max(v1s.length, v2s.length);
+ /* Project both polygons on axis */
+ for (int k = 0; k < maxLen; k++) {
+ if (k < v1s.length) {
+ Vector2d v1 = v1s[k];
+ double d = v1.x * aX + v1.y * aY;
+ if (d < minA) minA = d;
+ if (d > maxA) maxA = d;
+ }
+ if (k < v2s.length) {
+ Vector2d v2 = v2s[k];
+ double d = v2.x * aX + v2.y * aY;
+ if (d < minB) minB = d;
+ if (d > maxB) maxB = d;
+ }
+ /* Early-out if overlap found */
+ if (minA <= maxB && minB <= maxA) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test if the two convex polygons, given via their vertices, intersect.
+ *
+ * @param v1s
+ * the vertices of the first convex polygon
+ * @param v2s
+ * the vertices of the second convex polygon
+ * @return true
if the convex polygons intersect; false
otherwise
+ */
+ public static boolean testPolygonPolygon(Vector2d[] v1s, Vector2d[] v2s) {
+ /* Try to find a separating axis using the first polygon's edges */
+ for (int i = 0, j = v1s.length - 1; i < v1s.length; j = i, i++) {
+ Vector2d s = v1s[i], t = v1s[j];
+ if (separatingAxis(v1s, v2s, s.y - t.y, t.x - s.x))
+ return false;
+ }
+ /* Try to find a separating axis using the second polygon's edges */
+ for (int i = 0, j = v2s.length - 1; i < v2s.length; j = i, i++) {
+ Vector2d s = v2s[i], t = v2s[j];
+ if (separatingAxis(v1s, v2s, s.y - t.y, t.x - s.x))
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Intersectionf.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Intersectionf.java
new file mode 100644
index 000000000..fac99d454
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Intersectionf.java
@@ -0,0 +1,4789 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Contains intersection and distance tests for some 2D and 3D geometric primitives.
+ *
+ * @author Kai Burjack
+ */
+public class Intersectionf {
+
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point is the first vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_VERTEX_0 = 1;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point is the second vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_VERTEX_1 = 2;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point is the third vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_VERTEX_2 = 3;
+
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the edge between the first and second vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_EDGE_01 = 4;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the edge between the second and third vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_EDGE_12 = 5;
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the edge between the third and first vertex of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_EDGE_20 = 6;
+
+ /**
+ * Return value of
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)},
+ * {@link #findClosestPointOnTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3f)},
+ * {@link #findClosestPointOnTriangle(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #findClosestPointOnTriangle(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} or
+ * {@link #intersectSweptSphereTriangle}
+ * to signal that the closest point lies on the face of the triangle.
+ */
+ public static final int POINT_ON_TRIANGLE_FACE = 7;
+
+ /**
+ * Return value of {@link #intersectRayAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectRayAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the minimum x coordinate.
+ */
+ public static final int AAR_SIDE_MINX = 0;
+ /**
+ * Return value of {@link #intersectRayAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectRayAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the minimum y coordinate.
+ */
+ public static final int AAR_SIDE_MINY = 1;
+ /**
+ * Return value of {@link #intersectRayAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectRayAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the maximum x coordinate.
+ */
+ public static final int AAR_SIDE_MAXX = 2;
+ /**
+ * Return value of {@link #intersectRayAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectRayAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)}
+ * to indicate that the ray intersects the side of the axis-aligned rectangle with the maximum y coordinate.
+ */
+ public static final int AAR_SIDE_MAXY = 3;
+
+ /**
+ * Return value of {@link #intersectLineSegmentAab(float, float, float, float, float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)} to indicate that the line segment does not intersect the axis-aligned box;
+ * or return value of {@link #intersectLineSegmentAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} to indicate that the line segment does not intersect the axis-aligned rectangle.
+ */
+ public static final int OUTSIDE = -1;
+ /**
+ * Return value of {@link #intersectLineSegmentAab(float, float, float, float, float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)} to indicate that one end point of the line segment lies inside of the axis-aligned box;
+ * or return value of {@link #intersectLineSegmentAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} to indicate that one end point of the line segment lies inside of the axis-aligned rectangle.
+ */
+ public static final int ONE_INTERSECTION = 1;
+ /**
+ * Return value of {@link #intersectLineSegmentAab(float, float, float, float, float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)} to indicate that the line segment intersects two sides of the axis-aligned box
+ * or lies on an edge or a side of the box;
+ * or return value of {@link #intersectLineSegmentAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} to indicate that the line segment intersects two edges of the axis-aligned rectangle
+ * or lies on an edge of the rectangle.
+ */
+ public static final int TWO_INTERSECTION = 2;
+ /**
+ * Return value of {@link #intersectLineSegmentAab(float, float, float, float, float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)} to indicate that the line segment lies completely inside of the axis-aligned box;
+ * or return value of {@link #intersectLineSegmentAar(float, float, float, float, float, float, float, float, Vector2f)} and
+ * {@link #intersectLineSegmentAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)} to indicate that the line segment lies completely inside of the axis-aligned rectangle.
+ */
+ public static final int INSIDE = 3;
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the sphere with center
+ * (centerX, centerY, centerZ)
and radius
.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radius
+ * the radius of the sphere
+ * @return true
iff the plane intersects the sphere; false
otherwise
+ */
+ public static boolean testPlaneSphere(
+ float a, float b, float c, float d,
+ float centerX, float centerY, float centerZ, float radius) {
+ float denom = (float) Math.sqrt(a * a + b * b + c * c);
+ float dist = (a * centerX + b * centerY + c * centerZ + d) / denom;
+ return -radius <= dist && dist <= radius;
+ }
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the sphere with center
+ * (centerX, centerY, centerZ)
and radius
, and store the center of the circle of
+ * intersection in the (x, y, z)
components of the supplied vector and the radius of that circle in the w component.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radius
+ * the radius of the sphere
+ * @param intersectionCenterAndRadius
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff the plane intersects the sphere; false
otherwise
+ */
+ public static boolean intersectPlaneSphere(
+ float a, float b, float c, float d,
+ float centerX, float centerY, float centerZ, float radius,
+ Vector4f intersectionCenterAndRadius) {
+ float invDenom = Math.invsqrt(a * a + b * b + c * c);
+ float dist = (a * centerX + b * centerY + c * centerZ + d) * invDenom;
+ if (-radius <= dist && dist <= radius) {
+ intersectionCenterAndRadius.x = centerX + dist * a * invDenom;
+ intersectionCenterAndRadius.y = centerY + dist * b * invDenom;
+ intersectionCenterAndRadius.z = centerZ + dist * c * invDenom;
+ intersectionCenterAndRadius.w = (float) Math.sqrt(radius * radius - dist * dist);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the moving sphere with center
+ * (cX, cY, cZ)
, radius
and velocity (vX, vY, vZ)
, and store the point of intersection
+ * in the (x, y, z)
components of the supplied vector and the time of intersection in the w component.
+ *
+ * The normal vector (a, b, c)
of the plane equation needs to be normalized.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.5.3 "Intersecting Moving Sphere Against Plane"
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param cX
+ * the x coordinate of the center position of the sphere at t=0
+ * @param cY
+ * the y coordinate of the center position of the sphere at t=0
+ * @param cZ
+ * the z coordinate of the center position of the sphere at t=0
+ * @param radius
+ * the sphere's radius
+ * @param vX
+ * the x component of the velocity of the sphere
+ * @param vY
+ * the y component of the velocity of the sphere
+ * @param vZ
+ * the z component of the velocity of the sphere
+ * @param pointAndTime
+ * will hold the point and time of intersection (if any)
+ * @return true
iff the sphere intersects the plane; false
otherwise
+ */
+ public static boolean intersectPlaneSweptSphere(
+ float a, float b, float c, float d,
+ float cX, float cY, float cZ, float radius,
+ float vX, float vY, float vZ,
+ Vector4f pointAndTime) {
+ // Compute distance of sphere center to plane
+ float dist = a * cX + b * cY + c * cZ - d;
+ if (Math.abs(dist) <= radius) {
+ // The sphere is already overlapping the plane. Set time of
+ // intersection to zero and q to sphere center
+ pointAndTime.set(cX, cY, cZ, 0.0f);
+ return true;
+ }
+ float denom = a * vX + b * vY + c * vZ;
+ if (denom * dist >= 0.0f) {
+ // No intersection as sphere moving parallel to or away from plane
+ return false;
+ }
+ // Sphere is moving towards the plane
+ // Use +r in computations if sphere in front of plane, else -r
+ float r = dist > 0.0f ? radius : -radius;
+ float t = (r - dist) / denom;
+ pointAndTime.set(
+ cX + t * vX - r * a,
+ cY + t * vY - r * b,
+ cZ + t * vZ - r * c,
+ t);
+ return true;
+ }
+
+ /**
+ * Test whether the plane with the general plane equation a*x + b*y + c*z + d = 0 intersects the sphere moving from center
+ * position (t0X, t0Y, t0Z)
to (t1X, t1Y, t1Z)
and having the given radius
.
+ *
+ * The normal vector (a, b, c)
of the plane equation needs to be normalized.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.5.3 "Intersecting Moving Sphere Against Plane"
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param t0X
+ * the x coordinate of the start position of the sphere
+ * @param t0Y
+ * the y coordinate of the start position of the sphere
+ * @param t0Z
+ * the z coordinate of the start position of the sphere
+ * @param r
+ * the sphere's radius
+ * @param t1X
+ * the x coordinate of the end position of the sphere
+ * @param t1Y
+ * the y coordinate of the end position of the sphere
+ * @param t1Z
+ * the z coordinate of the end position of the sphere
+ * @return true
if the sphere intersects the plane; false
otherwise
+ */
+ public static boolean testPlaneSweptSphere(
+ float a, float b, float c, float d,
+ float t0X, float t0Y, float t0Z, float r,
+ float t1X, float t1Y, float t1Z) {
+ // Get the distance for both a and b from plane p
+ float adist = t0X * a + t0Y * b + t0Z * c - d;
+ float bdist = t1X * a + t1Y * b + t1Z * c - d;
+ // Intersects if on different sides of plane (distances have different signs)
+ if (adist * bdist < 0.0f) return true;
+ // Intersects if start or end position within radius from plane
+ if (Math.abs(adist) <= r || Math.abs(bdist) <= r) return true;
+ // No intersection
+ return false;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * intersects the plane with the general equation a*x + b*y + c*z + d = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the z coordinate of the maximum corner of the axis-aligned box
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return true
iff the axis-aligned box intersects the plane; false
otherwise
+ */
+ public static boolean testAabPlane(
+ float minX, float minY, float minZ,
+ float maxX, float maxY, float maxZ,
+ float a, float b, float c, float d) {
+ float pX, pY, pZ, nX, nY, nZ;
+ if (a > 0.0f) {
+ pX = maxX;
+ nX = minX;
+ } else {
+ pX = minX;
+ nX = maxX;
+ }
+ if (b > 0.0f) {
+ pY = maxY;
+ nY = minY;
+ } else {
+ pY = minY;
+ nY = maxY;
+ }
+ if (c > 0.0f) {
+ pZ = maxZ;
+ nZ = minZ;
+ } else {
+ pZ = minZ;
+ nZ = maxZ;
+ }
+ float distN = d + a * nX + b * nY + c * nZ;
+ float distP = d + a * pX + b * pY + c * pZ;
+ return distN <= 0.0f && distP >= 0.0f;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner min
and maximum corner max
+ * intersects the plane with the general equation a*x + b*y + c*z + d = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return true
iff the axis-aligned box intersects the plane; false
otherwise
+ */
+ public static boolean testAabPlane(Vector3fc min, Vector3fc max, float a, float b, float c, float d) {
+ return testAabPlane(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), a, b, c, d);
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner (minXA, minYA, minZA)
and maximum corner (maxXA, maxYA, maxZA)
+ * intersects the axis-aligned box with minimum corner (minXB, minYB, minZB)
and maximum corner (maxXB, maxYB, maxZB)
.
+ *
+ * @param minXA
+ * the x coordinate of the minimum corner of the first axis-aligned box
+ * @param minYA
+ * the y coordinate of the minimum corner of the first axis-aligned box
+ * @param minZA
+ * the z coordinate of the minimum corner of the first axis-aligned box
+ * @param maxXA
+ * the x coordinate of the maximum corner of the first axis-aligned box
+ * @param maxYA
+ * the y coordinate of the maximum corner of the first axis-aligned box
+ * @param maxZA
+ * the z coordinate of the maximum corner of the first axis-aligned box
+ * @param minXB
+ * the x coordinate of the minimum corner of the second axis-aligned box
+ * @param minYB
+ * the y coordinate of the minimum corner of the second axis-aligned box
+ * @param minZB
+ * the z coordinate of the minimum corner of the second axis-aligned box
+ * @param maxXB
+ * the x coordinate of the maximum corner of the second axis-aligned box
+ * @param maxYB
+ * the y coordinate of the maximum corner of the second axis-aligned box
+ * @param maxZB
+ * the z coordinate of the maximum corner of the second axis-aligned box
+ * @return true
iff both axis-aligned boxes intersect; false
otherwise
+ */
+ public static boolean testAabAab(
+ float minXA, float minYA, float minZA,
+ float maxXA, float maxYA, float maxZA,
+ float minXB, float minYB, float minZB,
+ float maxXB, float maxYB, float maxZB) {
+ return maxXA >= minXB && maxYA >= minYB && maxZA >= minZB &&
+ minXA <= maxXB && minYA <= maxYB && minZA <= maxZB;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner minA
and maximum corner maxA
+ * intersects the axis-aligned box with minimum corner minB
and maximum corner maxB
.
+ *
+ * @param minA
+ * the minimum corner of the first axis-aligned box
+ * @param maxA
+ * the maximum corner of the first axis-aligned box
+ * @param minB
+ * the minimum corner of the second axis-aligned box
+ * @param maxB
+ * the maximum corner of the second axis-aligned box
+ * @return true
iff both axis-aligned boxes intersect; false
otherwise
+ */
+ public static boolean testAabAab(Vector3fc minA, Vector3fc maxA, Vector3fc minB, Vector3fc maxB) {
+ return testAabAab(minA.x(), minA.y(), minA.z(), maxA.x(), maxA.y(), maxA.z(), minB.x(), minB.y(), minB.z(), maxB.x(), maxB.y(), maxB.z());
+ }
+
+ /**
+ * Test whether two oriented boxes given via their center position, orientation and half-size, intersect.
+ *
+ * The orientation of a box is given as three unit vectors spanning the local orthonormal basis of the box.
+ *
+ * The size is given as the half-size along each of the unit vectors defining the orthonormal basis.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 4.4.1 "OBB-OBB Intersection"
+ *
+ * @param b0c
+ * the center of the first box
+ * @param b0uX
+ * the local X unit vector of the first box
+ * @param b0uY
+ * the local Y unit vector of the first box
+ * @param b0uZ
+ * the local Z unit vector of the first box
+ * @param b0hs
+ * the half-size of the first box
+ * @param b1c
+ * the center of the second box
+ * @param b1uX
+ * the local X unit vector of the second box
+ * @param b1uY
+ * the local Y unit vector of the second box
+ * @param b1uZ
+ * the local Z unit vector of the second box
+ * @param b1hs
+ * the half-size of the second box
+ * @return true
if both boxes intersect; false
otherwise
+ */
+ public static boolean testObOb(
+ Vector3f b0c, Vector3f b0uX, Vector3f b0uY, Vector3f b0uZ, Vector3f b0hs,
+ Vector3f b1c, Vector3f b1uX, Vector3f b1uY, Vector3f b1uZ, Vector3f b1hs) {
+ return testObOb(
+ b0c.x, b0c.y, b0c.z, b0uX.x, b0uX.y, b0uX.z, b0uY.x, b0uY.y, b0uY.z, b0uZ.x, b0uZ.y, b0uZ.z, b0hs.x, b0hs.y, b0hs.z,
+ b1c.x, b1c.y, b1c.z, b1uX.x, b1uX.y, b1uX.z, b1uY.x, b1uY.y, b1uY.z, b1uZ.x, b1uZ.y, b1uZ.z, b1hs.x, b1hs.y, b1hs.z);
+ }
+
+ /**
+ * Test whether two oriented boxes given via their center position, orientation and half-size, intersect.
+ *
+ * The orientation of a box is given as three unit vectors spanning the local orthonormal basis of the box.
+ *
+ * The size is given as the half-size along each of the unit vectors defining the orthonormal basis.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 4.4.1 "OBB-OBB Intersection"
+ *
+ * @param b0cX
+ * the x coordinate of the center of the first box
+ * @param b0cY
+ * the y coordinate of the center of the first box
+ * @param b0cZ
+ * the z coordinate of the center of the first box
+ * @param b0uXx
+ * the x coordinate of the local X unit vector of the first box
+ * @param b0uXy
+ * the y coordinate of the local X unit vector of the first box
+ * @param b0uXz
+ * the z coordinate of the local X unit vector of the first box
+ * @param b0uYx
+ * the x coordinate of the local Y unit vector of the first box
+ * @param b0uYy
+ * the y coordinate of the local Y unit vector of the first box
+ * @param b0uYz
+ * the z coordinate of the local Y unit vector of the first box
+ * @param b0uZx
+ * the x coordinate of the local Z unit vector of the first box
+ * @param b0uZy
+ * the y coordinate of the local Z unit vector of the first box
+ * @param b0uZz
+ * the z coordinate of the local Z unit vector of the first box
+ * @param b0hsX
+ * the half-size of the first box along its local X axis
+ * @param b0hsY
+ * the half-size of the first box along its local Y axis
+ * @param b0hsZ
+ * the half-size of the first box along its local Z axis
+ * @param b1cX
+ * the x coordinate of the center of the second box
+ * @param b1cY
+ * the y coordinate of the center of the second box
+ * @param b1cZ
+ * the z coordinate of the center of the second box
+ * @param b1uXx
+ * the x coordinate of the local X unit vector of the second box
+ * @param b1uXy
+ * the y coordinate of the local X unit vector of the second box
+ * @param b1uXz
+ * the z coordinate of the local X unit vector of the second box
+ * @param b1uYx
+ * the x coordinate of the local Y unit vector of the second box
+ * @param b1uYy
+ * the y coordinate of the local Y unit vector of the second box
+ * @param b1uYz
+ * the z coordinate of the local Y unit vector of the second box
+ * @param b1uZx
+ * the x coordinate of the local Z unit vector of the second box
+ * @param b1uZy
+ * the y coordinate of the local Z unit vector of the second box
+ * @param b1uZz
+ * the z coordinate of the local Z unit vector of the second box
+ * @param b1hsX
+ * the half-size of the second box along its local X axis
+ * @param b1hsY
+ * the half-size of the second box along its local Y axis
+ * @param b1hsZ
+ * the half-size of the second box along its local Z axis
+ * @return true
if both boxes intersect; false
otherwise
+ */
+ public static boolean testObOb(
+ float b0cX, float b0cY, float b0cZ, float b0uXx, float b0uXy, float b0uXz, float b0uYx, float b0uYy, float b0uYz, float b0uZx, float b0uZy, float b0uZz, float b0hsX, float b0hsY, float b0hsZ,
+ float b1cX, float b1cY, float b1cZ, float b1uXx, float b1uXy, float b1uXz, float b1uYx, float b1uYy, float b1uYz, float b1uZx, float b1uZy, float b1uZz, float b1hsX, float b1hsY, float b1hsZ) {
+ float ra, rb;
+ // Compute rotation matrix expressing b in a's coordinate frame
+ float rm00 = b0uXx * b1uXx + b0uYx * b1uYx + b0uZx * b1uZx;
+ float rm10 = b0uXx * b1uXy + b0uYx * b1uYy + b0uZx * b1uZy;
+ float rm20 = b0uXx * b1uXz + b0uYx * b1uYz + b0uZx * b1uZz;
+ float rm01 = b0uXy * b1uXx + b0uYy * b1uYx + b0uZy * b1uZx;
+ float rm11 = b0uXy * b1uXy + b0uYy * b1uYy + b0uZy * b1uZy;
+ float rm21 = b0uXy * b1uXz + b0uYy * b1uYz + b0uZy * b1uZz;
+ float rm02 = b0uXz * b1uXx + b0uYz * b1uYx + b0uZz * b1uZx;
+ float rm12 = b0uXz * b1uXy + b0uYz * b1uYy + b0uZz * b1uZy;
+ float rm22 = b0uXz * b1uXz + b0uYz * b1uYz + b0uZz * b1uZz;
+ // Compute common subexpressions. Add in an epsilon term to
+ // counteract arithmetic errors when two edges are parallel and
+ // their cross product is (near) null (see text for details)
+ float EPSILON = 1E-5f;
+ float arm00 = Math.abs(rm00) + EPSILON;
+ float arm01 = Math.abs(rm01) + EPSILON;
+ float arm02 = Math.abs(rm02) + EPSILON;
+ float arm10 = Math.abs(rm10) + EPSILON;
+ float arm11 = Math.abs(rm11) + EPSILON;
+ float arm12 = Math.abs(rm12) + EPSILON;
+ float arm20 = Math.abs(rm20) + EPSILON;
+ float arm21 = Math.abs(rm21) + EPSILON;
+ float arm22 = Math.abs(rm22) + EPSILON;
+ // Compute translation vector t
+ float tx = b1cX - b0cX, ty = b1cY - b0cY, tz = b1cZ - b0cZ;
+ // Bring translation into a's coordinate frame
+ float tax = tx * b0uXx + ty * b0uXy + tz * b0uXz;
+ float tay = tx * b0uYx + ty * b0uYy + tz * b0uYz;
+ float taz = tx * b0uZx + ty * b0uZy + tz * b0uZz;
+ // Test axes L = A0, L = A1, L = A2
+ ra = b0hsX;
+ rb = b1hsX * arm00 + b1hsY * arm01 + b1hsZ * arm02;
+ if (Math.abs(tax) > ra + rb) return false;
+ ra = b0hsY;
+ rb = b1hsX * arm10 + b1hsY * arm11 + b1hsZ * arm12;
+ if (Math.abs(tay) > ra + rb) return false;
+ ra = b0hsZ;
+ rb = b1hsX * arm20 + b1hsY * arm21 + b1hsZ * arm22;
+ if (Math.abs(taz) > ra + rb) return false;
+ // Test axes L = B0, L = B1, L = B2
+ ra = b0hsX * arm00 + b0hsY * arm10 + b0hsZ * arm20;
+ rb = b1hsX;
+ if (Math.abs(tax * rm00 + tay * rm10 + taz * rm20) > ra + rb) return false;
+ ra = b0hsX * arm01 + b0hsY * arm11 + b0hsZ * arm21;
+ rb = b1hsY;
+ if (Math.abs(tax * rm01 + tay * rm11 + taz * rm21) > ra + rb) return false;
+ ra = b0hsX * arm02 + b0hsY * arm12 + b0hsZ * arm22;
+ rb = b1hsZ;
+ if (Math.abs(tax * rm02 + tay * rm12 + taz * rm22) > ra + rb) return false;
+ // Test axis L = A0 x B0
+ ra = b0hsY * arm20 + b0hsZ * arm10;
+ rb = b1hsY * arm02 + b1hsZ * arm01;
+ if (Math.abs(taz * rm10 - tay * rm20) > ra + rb) return false;
+ // Test axis L = A0 x B1
+ ra = b0hsY * arm21 + b0hsZ * arm11;
+ rb = b1hsX * arm02 + b1hsZ * arm00;
+ if (Math.abs(taz * rm11 - tay * rm21) > ra + rb) return false;
+ // Test axis L = A0 x B2
+ ra = b0hsY * arm22 + b0hsZ * arm12;
+ rb = b1hsX * arm01 + b1hsY * arm00;
+ if (Math.abs(taz * rm12 - tay * rm22) > ra + rb) return false;
+ // Test axis L = A1 x B0
+ ra = b0hsX * arm20 + b0hsZ * arm00;
+ rb = b1hsY * arm12 + b1hsZ * arm11;
+ if (Math.abs(tax * rm20 - taz * rm00) > ra + rb) return false;
+ // Test axis L = A1 x B1
+ ra = b0hsX * arm21 + b0hsZ * arm01;
+ rb = b1hsX * arm12 + b1hsZ * arm10;
+ if (Math.abs(tax * rm21 - taz * rm01) > ra + rb) return false;
+ // Test axis L = A1 x B2
+ ra = b0hsX * arm22 + b0hsZ * arm02;
+ rb = b1hsX * arm11 + b1hsY * arm10;
+ if (Math.abs(tax * rm22 - taz * rm02) > ra + rb) return false;
+ // Test axis L = A2 x B0
+ ra = b0hsX * arm10 + b0hsY * arm00;
+ rb = b1hsY * arm22 + b1hsZ * arm21;
+ if (Math.abs(tay * rm00 - tax * rm10) > ra + rb) return false;
+ // Test axis L = A2 x B1
+ ra = b0hsX * arm11 + b0hsY * arm01;
+ rb = b1hsX * arm22 + b1hsZ * arm20;
+ if (Math.abs(tay * rm01 - tax * rm11) > ra + rb) return false;
+ // Test axis L = A2 x B2
+ ra = b0hsX * arm12 + b0hsY * arm02;
+ rb = b1hsX * arm21 + b1hsY * arm20;
+ if (Math.abs(tay * rm02 - tax * rm12) > ra + rb) return false;
+ // Since no separating axis is found, the OBBs must be intersecting
+ return true;
+ }
+
+ /**
+ * Test whether the one sphere with center (aX, aY, aZ)
and square radius radiusSquaredA
intersects the other
+ * sphere with center (bX, bY, bZ)
and square radius radiusSquaredB
, and store the center of the circle of
+ * intersection in the (x, y, z)
components of the supplied vector and the radius of that circle in the w component.
+ *
+ * The normal vector of the circle of intersection can simply be obtained by subtracting the center of either sphere from the other.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param aX
+ * the x coordinate of the first sphere's center
+ * @param aY
+ * the y coordinate of the first sphere's center
+ * @param aZ
+ * the z coordinate of the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param bX
+ * the x coordinate of the second sphere's center
+ * @param bY
+ * the y coordinate of the second sphere's center
+ * @param bZ
+ * the z coordinate of the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @param centerAndRadiusOfIntersectionCircle
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean intersectSphereSphere(
+ float aX, float aY, float aZ, float radiusSquaredA,
+ float bX, float bY, float bZ, float radiusSquaredB,
+ Vector4f centerAndRadiusOfIntersectionCircle) {
+ float dX = bX - aX, dY = bY - aY, dZ = bZ - aZ;
+ float distSquared = dX * dX + dY * dY + dZ * dZ;
+ float h = 0.5f + (radiusSquaredA - radiusSquaredB) / distSquared;
+ float r_i = radiusSquaredA - h * h * distSquared;
+ if (r_i >= 0.0f) {
+ centerAndRadiusOfIntersectionCircle.x = aX + h * dX;
+ centerAndRadiusOfIntersectionCircle.y = aY + h * dY;
+ centerAndRadiusOfIntersectionCircle.z = aZ + h * dZ;
+ centerAndRadiusOfIntersectionCircle.w = (float) Math.sqrt(r_i);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the one sphere with center centerA
and square radius radiusSquaredA
intersects the other
+ * sphere with center centerB
and square radius radiusSquaredB
, and store the center of the circle of
+ * intersection in the (x, y, z)
components of the supplied vector and the radius of that circle in the w component.
+ *
+ * The normal vector of the circle of intersection can simply be obtained by subtracting the center of either sphere from the other.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param centerB
+ * the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @param centerAndRadiusOfIntersectionCircle
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean intersectSphereSphere(Vector3fc centerA, float radiusSquaredA, Vector3fc centerB, float radiusSquaredB, Vector4f centerAndRadiusOfIntersectionCircle) {
+ return intersectSphereSphere(centerA.x(), centerA.y(), centerA.z(), radiusSquaredA, centerB.x(), centerB.y(), centerB.z(), radiusSquaredB, centerAndRadiusOfIntersectionCircle);
+ }
+
+ /**
+ * Test whether the given sphere with center (sX, sY, sZ)
intersects the triangle given by its three vertices, and if they intersect
+ * store the point of intersection into result
.
+ *
+ * This method also returns whether the point of intersection is on one of the triangle's vertices, edges or on the face.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.2.7 "Testing Sphere Against Triangle"
+ *
+ * @param sX
+ * the x coordinate of the sphere's center
+ * @param sY
+ * the y coordinate of the sphere's center
+ * @param sZ
+ * the z coordinate of the sphere's center
+ * @param sR
+ * the sphere's radius
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v0Z
+ * the z coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v1Z
+ * the z coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param v2Z
+ * the z coordinate of the third vertex of the triangle
+ * @param result
+ * will hold the point of intersection
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE} or 0
+ */
+ public static int intersectSphereTriangle(
+ float sX, float sY, float sZ, float sR,
+ float v0X, float v0Y, float v0Z,
+ float v1X, float v1Y, float v1Z,
+ float v2X, float v2Y, float v2Z,
+ Vector3f result) {
+ int closest = findClosestPointOnTriangle(v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, sX, sY, sZ, result);
+ float vX = result.x - sX, vY = result.y - sY, vZ = result.z - sZ;
+ float dot = vX * vX + vY * vY + vZ * vZ;
+ if (dot <= sR * sR) {
+ return closest;
+ }
+ return 0;
+ }
+
+ /**
+ * Test whether the one sphere with center (aX, aY, aZ)
and square radius radiusSquaredA
intersects the other
+ * sphere with center (bX, bY, bZ)
and square radius radiusSquaredB
.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param aX
+ * the x coordinate of the first sphere's center
+ * @param aY
+ * the y coordinate of the first sphere's center
+ * @param aZ
+ * the z coordinate of the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param bX
+ * the x coordinate of the second sphere's center
+ * @param bY
+ * the y coordinate of the second sphere's center
+ * @param bZ
+ * the z coordinate of the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean testSphereSphere(
+ float aX, float aY, float aZ, float radiusSquaredA,
+ float bX, float bY, float bZ, float radiusSquaredB) {
+ float dX = bX - aX, dY = bY - aY, dZ = bZ - aZ;
+ float distSquared = dX * dX + dY * dY + dZ * dZ;
+ float h = 0.5f + (radiusSquaredA - radiusSquaredB) / distSquared;
+ float r_i = radiusSquaredA - h * h * distSquared;
+ return r_i >= 0.0f;
+ }
+
+ /**
+ * Test whether the one sphere with center centerA
and square radius radiusSquaredA
intersects the other
+ * sphere with center centerB
and square radius radiusSquaredB
.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first sphere's center
+ * @param radiusSquaredA
+ * the square of the first sphere's radius
+ * @param centerB
+ * the second sphere's center
+ * @param radiusSquaredB
+ * the square of the second sphere's radius
+ * @return true
iff both spheres intersect; false
otherwise
+ */
+ public static boolean testSphereSphere(Vector3fc centerA, float radiusSquaredA, Vector3fc centerB, float radiusSquaredB) {
+ return testSphereSphere(centerA.x(), centerA.y(), centerA.z(), radiusSquaredA, centerB.x(), centerB.y(), centerB.z(), radiusSquaredB);
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY, pointZ)
to the plane specified via its general plane equation
+ * a*x + b*y + c*z + d = 0.
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param pointZ
+ * the z coordinate of the point
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return the distance between the point and the plane
+ */
+ public static float distancePointPlane(float pointX, float pointY, float pointZ, float a, float b, float c, float d) {
+ float denom = (float) Math.sqrt(a * a + b * b + c * c);
+ return (a * pointX + b * pointY + c * pointZ + d) / denom;
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY, pointZ)
to the plane of the triangle specified by its three points
+ * (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * If the point lies on the front-facing side of the triangle's plane, that is, if the triangle has counter-clockwise winding order
+ * as seen from the point, then this method returns a positive number.
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param pointZ
+ * the z coordinate of the point
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v0Z
+ * the z coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v1Z
+ * the z coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param v2Z
+ * the z coordinate of the third vertex of the triangle
+ * @return the signed distance between the point and the plane of the triangle
+ */
+ public static float distancePointPlane(float pointX, float pointY, float pointZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z) {
+ float v1Y0Y = v1Y - v0Y;
+ float v2Z0Z = v2Z - v0Z;
+ float v2Y0Y = v2Y - v0Y;
+ float v1Z0Z = v1Z - v0Z;
+ float v2X0X = v2X - v0X;
+ float v1X0X = v1X - v0X;
+ float a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z;
+ float b = v1Z0Z * v2X0X - v2Z0Z * v1X0X;
+ float c = v1X0X * v2Y0Y - v2X0X * v1Y0Y;
+ float d = -(a * v0X + b * v0Y + c * v0Z);
+ return distancePointPlane(pointX, pointY, pointZ, a, b, c, d);
+ }
+
+ /**
+ * Test whether the ray with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
intersects the plane
+ * containing the given point (pointX, pointY, pointZ)
and having the normal (normalX, normalY, normalZ)
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the plane, because it is either parallel to the plane or its direction points
+ * away from the plane or the ray's origin is on the negative side of the plane (i.e. the plane's normal points away from the ray's origin).
+ *
+ * Reference: https://www.siggraph.org/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param pointX
+ * the x coordinate of a point on the plane
+ * @param pointY
+ * the y coordinate of a point on the plane
+ * @param pointZ
+ * the z coordinate of a point on the plane
+ * @param normalX
+ * the x coordinate of the plane's normal
+ * @param normalY
+ * the y coordinate of the plane's normal
+ * @param normalZ
+ * the z coordinate of the plane's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the plane
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the plane; -1.0
otherwise
+ */
+ public static float intersectRayPlane(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float pointX, float pointY, float pointZ, float normalX, float normalY, float normalZ, float epsilon) {
+ float denom = normalX * dirX + normalY * dirY + normalZ * dirZ;
+ if (denom < epsilon) {
+ float t = ((pointX - originX) * normalX + (pointY - originY) * normalY + (pointZ - originZ) * normalZ) / denom;
+ if (t >= 0.0f)
+ return t;
+ }
+ return -1.0f;
+ }
+
+ /**
+ * Test whether the ray with given origin
and direction dir
intersects the plane
+ * containing the given point
and having the given normal
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the plane, because it is either parallel to the plane or its direction points
+ * away from the plane or the ray's origin is on the negative side of the plane (i.e. the plane's normal points away from the ray's origin).
+ *
+ * Reference: https://www.siggraph.org/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param point
+ * a point on the plane
+ * @param normal
+ * the plane's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the plane
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the plane; -1.0
otherwise
+ */
+ public static float intersectRayPlane(Vector3fc origin, Vector3fc dir, Vector3fc point, Vector3fc normal, float epsilon) {
+ return intersectRayPlane(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), point.x(), point.y(), point.z(), normal.x(), normal.y(), normal.z(), epsilon);
+ }
+
+ /**
+ * Test whether the ray with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
intersects the plane
+ * given as the general plane equation a*x + b*y + c*z + d = 0, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the plane, because it is either parallel to the plane or its direction points
+ * away from the plane or the ray's origin is on the negative side of the plane (i.e. the plane's normal points away from the ray's origin).
+ *
+ * Reference: https://www.siggraph.org/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the plane
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the plane; -1.0
otherwise
+ */
+ public static float intersectRayPlane(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float a, float b, float c, float d, float epsilon) {
+ float denom = a * dirX + b * dirY + c * dirZ;
+ if (denom < 0.0f) {
+ float t = -(a * originX + b * originY + c * originZ + d) / denom;
+ if (t >= 0.0f)
+ return t;
+ }
+ return -1.0f;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * intersects the sphere with the given center (centerX, centerY, centerZ)
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the z coordinate of the maximum corner of the axis-aligned box
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the square of the sphere's radius
+ * @return true
iff the axis-aligned box intersects the sphere; false
otherwise
+ */
+ public static boolean testAabSphere(
+ float minX, float minY, float minZ,
+ float maxX, float maxY, float maxZ,
+ float centerX, float centerY, float centerZ, float radiusSquared) {
+ float radius2 = radiusSquared;
+ if (centerX < minX) {
+ float d = (centerX - minX);
+ radius2 -= d * d;
+ } else if (centerX > maxX) {
+ float d = (centerX - maxX);
+ radius2 -= d * d;
+ }
+ if (centerY < minY) {
+ float d = (centerY - minY);
+ radius2 -= d * d;
+ } else if (centerY > maxY) {
+ float d = (centerY - maxY);
+ radius2 -= d * d;
+ }
+ if (centerZ < minZ) {
+ float d = (centerZ - minZ);
+ radius2 -= d * d;
+ } else if (centerZ > maxZ) {
+ float d = (centerZ - maxZ);
+ radius2 -= d * d;
+ }
+ return radius2 >= 0.0f;
+ }
+
+ /**
+ * Test whether the axis-aligned box with minimum corner min
and maximum corner max
+ * intersects the sphere with the given center
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the squared of the sphere's radius
+ * @return true
iff the axis-aligned box intersects the sphere; false
otherwise
+ */
+ public static boolean testAabSphere(Vector3fc min, Vector3fc max, Vector3fc center, float radiusSquared) {
+ return testAabSphere(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), center.x(), center.y(), center.z(), radiusSquared);
+ }
+
+ /**
+ * Find the point on the given plane which is closest to the specified point (pX, pY, pZ)
and store the result in result
.
+ *
+ * @param aX
+ * the x coordinate of one point on the plane
+ * @param aY
+ * the y coordinate of one point on the plane
+ * @param aZ
+ * the z coordinate of one point on the plane
+ * @param nX
+ * the x coordinate of the unit normal of the plane
+ * @param nY
+ * the y coordinate of the unit normal of the plane
+ * @param nZ
+ * the z coordinate of the unit normal of the plane
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param result
+ * will hold the result
+ * @return result
+ */
+ public static Vector3f findClosestPointOnPlane(float aX, float aY, float aZ, float nX, float nY, float nZ, float pX, float pY, float pZ, Vector3f result) {
+ float d = -(nX * aX + nY * aY + nZ * aZ);
+ float t = nX * pX + nY * pY + nZ * pZ - d;
+ result.x = pX - t * nX;
+ result.y = pY - t * nY;
+ result.z = pZ - t * nZ;
+ return result;
+ }
+
+ /**
+ * Find the point on the given line segment which is closest to the specified point (pX, pY, pZ)
, and store the result in result
.
+ *
+ * @param aX
+ * the x coordinate of the first end point of the line segment
+ * @param aY
+ * the y coordinate of the first end point of the line segment
+ * @param aZ
+ * the z coordinate of the first end point of the line segment
+ * @param bX
+ * the x coordinate of the second end point of the line segment
+ * @param bY
+ * the y coordinate of the second end point of the line segment
+ * @param bZ
+ * the z coordinate of the second end point of the line segment
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param result
+ * will hold the result
+ * @return result
+ */
+ public static Vector3f findClosestPointOnLineSegment(float aX, float aY, float aZ, float bX, float bY, float bZ, float pX, float pY, float pZ, Vector3f result) {
+ float abX = bX - aX, abY = bY - aY, abZ = bZ - aZ;
+ float t = ((pX - aX) * abX + (pY - aY) * abY + (pZ - aZ) * abZ) / (abX * abX + abY * abY + abZ * abZ);
+ if (t < 0.0f) t = 0.0f;
+ if (t > 1.0f) t = 1.0f;
+ result.x = aX + t * abX;
+ result.y = aY + t * abY;
+ result.z = aZ + t * abZ;
+ return result;
+ }
+
+ /**
+ * Find the closest points on the two line segments, store the point on the first line segment in resultA
and
+ * the point on the second line segment in resultB
, and return the square distance between both points.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.9 "Closest Points of Two Line Segments"
+ *
+ * @param a0X
+ * the x coordinate of the first line segment's first end point
+ * @param a0Y
+ * the y coordinate of the first line segment's first end point
+ * @param a0Z
+ * the z coordinate of the first line segment's first end point
+ * @param a1X
+ * the x coordinate of the first line segment's second end point
+ * @param a1Y
+ * the y coordinate of the first line segment's second end point
+ * @param a1Z
+ * the z coordinate of the first line segment's second end point
+ * @param b0X
+ * the x coordinate of the second line segment's first end point
+ * @param b0Y
+ * the y coordinate of the second line segment's first end point
+ * @param b0Z
+ * the z coordinate of the second line segment's first end point
+ * @param b1X
+ * the x coordinate of the second line segment's second end point
+ * @param b1Y
+ * the y coordinate of the second line segment's second end point
+ * @param b1Z
+ * the z coordinate of the second line segment's second end point
+ * @param resultA
+ * will hold the point on the first line segment
+ * @param resultB
+ * will hold the point on the second line segment
+ * @return the square distance between the two closest points
+ */
+ public static float findClosestPointsLineSegments(
+ float a0X, float a0Y, float a0Z, float a1X, float a1Y, float a1Z,
+ float b0X, float b0Y, float b0Z, float b1X, float b1Y, float b1Z,
+ Vector3f resultA, Vector3f resultB) {
+ float d1x = a1X - a0X, d1y = a1Y - a0Y, d1z = a1Z - a0Z;
+ float d2x = b1X - b0X, d2y = b1Y - b0Y, d2z = b1Z - b0Z;
+ float rX = a0X - b0X, rY = a0Y - b0Y, rZ = a0Z - b0Z;
+ float a = d1x * d1x + d1y * d1y + d1z * d1z;
+ float e = d2x * d2x + d2y * d2y + d2z * d2z;
+ float f = d2x * rX + d2y * rY + d2z * rZ;
+ float EPSILON = 1E-5f;
+ float s, t;
+ if (a <= EPSILON && e <= EPSILON) {
+ // Both segments degenerate into points
+ resultA.set(a0X, a0Y, a0Z);
+ resultB.set(b0X, b0Y, b0Z);
+ return resultA.dot(resultB);
+ }
+ if (a <= EPSILON) {
+ // First segment degenerates into a point
+ s = 0.0f;
+ t = f / e;
+ t = Math.min(Math.max(t, 0.0f), 1.0f);
+ } else {
+ float c = d1x * rX + d1y * rY + d1z * rZ;
+ if (e <= EPSILON) {
+ // Second segment degenerates into a point
+ t = 0.0f;
+ s = Math.min(Math.max(-c / a, 0.0f), 1.0f);
+ } else {
+ // The general nondegenerate case starts here
+ float b = d1x * d2x + d1y * d2y + d1z * d2z;
+ float denom = a * e - b * b;
+ // If segments not parallel, compute closest point on L1 to L2 and
+ // clamp to segment S1. Else pick arbitrary s (here 0)
+ if (denom != 0.0)
+ s = Math.min(Math.max((b*f - c*e) / denom, 0.0f), 1.0f);
+ else
+ s = 0.0f;
+ // Compute point on L2 closest to S1(s) using
+ // t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e
+ t = (b * s + f) / e;
+ // If t in [0,1] done. Else clamp t, recompute s for the new value
+ // of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a
+ // and clamp s to [0, 1]
+ if (t < 0.0) {
+ t = 0.0f;
+ s = Math.min(Math.max(-c / a, 0.0f), 1.0f);
+ } else if (t > 1.0) {
+ t = 1.0f;
+ s = Math.min(Math.max((b - c) / a, 0.0f), 1.0f);
+ }
+ }
+ }
+ resultA.set(a0X + d1x * s, a0Y + d1y * s, a0Z + d1z * s);
+ resultB.set(b0X + d2x * t, b0Y + d2y * t, b0Z + d2z * t);
+ float dX = resultA.x - resultB.x, dY = resultA.y - resultB.y, dZ = resultA.z - resultB.z;
+ return dX*dX + dY*dY + dZ*dZ;
+ }
+
+ /**
+ * Find the closest points on a line segment and a triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.10 "Closest Points of a Line Segment and a Triangle"
+ *
+ * @param aX
+ * the x coordinate of the line segment's first end point
+ * @param aY
+ * the y coordinate of the line segment's first end point
+ * @param aZ
+ * the z coordinate of the line segment's first end point
+ * @param bX
+ * the x coordinate of the line segment's second end point
+ * @param bY
+ * the y coordinate of the line segment's second end point
+ * @param bZ
+ * the z coordinate of the line segment's second end point
+ * @param v0X
+ * the x coordinate of the triangle's first vertex
+ * @param v0Y
+ * the y coordinate of the triangle's first vertex
+ * @param v0Z
+ * the z coordinate of the triangle's first vertex
+ * @param v1X
+ * the x coordinate of the triangle's second vertex
+ * @param v1Y
+ * the y coordinate of the triangle's second vertex
+ * @param v1Z
+ * the z coordinate of the triangle's second vertex
+ * @param v2X
+ * the x coordinate of the triangle's third vertex
+ * @param v2Y
+ * the y coordinate of the triangle's third vertex
+ * @param v2Z
+ * the z coordinate of the triangle's third vertex
+ * @param lineSegmentResult
+ * will hold the closest point on the line segment
+ * @param triangleResult
+ * will hold the closest point on the triangle
+ * @return the square distance of the closest points
+ */
+ public static float findClosestPointsLineSegmentTriangle(
+ float aX, float aY, float aZ, float bX, float bY, float bZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ Vector3f lineSegmentResult, Vector3f triangleResult) {
+ float min, d;
+ float minlsX, minlsY, minlsZ, mintX, mintY, mintZ;
+ // AB -> V0V1
+ d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, lineSegmentResult, triangleResult);
+ min = d;
+ minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z;
+ mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z;
+ // AB -> V1V2
+ d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v1X, v1Y, v1Z, v2X, v2Y, v2Z, lineSegmentResult, triangleResult);
+ if (d < min) {
+ min = d;
+ minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z;
+ mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z;
+ }
+ // AB -> V2V0
+ d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v2X, v2Y, v2Z, v0X, v0Y, v0Z, lineSegmentResult, triangleResult);
+ if (d < min) {
+ min = d;
+ minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z;
+ mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z;
+ }
+ // segment endpoint A and plane of triangle (when A projects inside V0V1V2)
+ boolean computed = false;
+ float a = Float.NaN, b = Float.NaN, c = Float.NaN, nd = Float.NaN;
+ if (testPointInTriangle(aX, aY, aZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z)) {
+ float v1Y0Y = v1Y - v0Y;
+ float v2Z0Z = v2Z - v0Z;
+ float v2Y0Y = v2Y - v0Y;
+ float v1Z0Z = v1Z - v0Z;
+ float v2X0X = v2X - v0X;
+ float v1X0X = v1X - v0X;
+ a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z;
+ b = v1Z0Z * v2X0X - v2Z0Z * v1X0X;
+ c = v1X0X * v2Y0Y - v2X0X * v1Y0Y;
+ computed = true;
+ float invLen = Math.invsqrt(a*a + b*b + c*c);
+ a *= invLen; b *= invLen; c *= invLen;
+ nd = -(a * v0X + b * v0Y + c * v0Z);
+ d = (a * aX + b * aY + c * aZ + nd);
+ float l = d;
+ d *= d;
+ if (d < min) {
+ min = d;
+ minlsX = aX; minlsY = aY; minlsZ = aZ;
+ mintX = aX - a*l; mintY = aY - b*l; mintZ = aZ - c*l;
+ }
+ }
+ // segment endpoint B and plane of triangle (when B projects inside V0V1V2)
+ if (testPointInTriangle(bX, bY, bZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z)) {
+ if (!computed) {
+ float v1Y0Y = v1Y - v0Y;
+ float v2Z0Z = v2Z - v0Z;
+ float v2Y0Y = v2Y - v0Y;
+ float v1Z0Z = v1Z - v0Z;
+ float v2X0X = v2X - v0X;
+ float v1X0X = v1X - v0X;
+ a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z;
+ b = v1Z0Z * v2X0X - v2Z0Z * v1X0X;
+ c = v1X0X * v2Y0Y - v2X0X * v1Y0Y;
+ float invLen = Math.invsqrt(a*a + b*b + c*c);
+ a *= invLen; b *= invLen; c *= invLen;
+ nd = -(a * v0X + b * v0Y + c * v0Z);
+ }
+ d = (a * bX + b * bY + c * bZ + nd);
+ float l = d;
+ d *= d;
+ if (d < min) {
+ min = d;
+ minlsX = bX; minlsY = bY; minlsZ = bZ;
+ mintX = bX - a*l; mintY = bY - b*l; mintZ = bZ - c*l;
+ }
+ }
+ lineSegmentResult.set(minlsX, minlsY, minlsZ);
+ triangleResult.set(mintX, mintY, mintZ);
+ return min;
+ }
+
+ /**
+ * Determine the closest point on the triangle with the given vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
, (v2X, v2Y, v2Z)
+ * between that triangle and the given point (pX, pY, pZ)
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v0Z
+ * the z coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v1Z
+ * the z coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param v2Z
+ * the z coordinate of the third vertex of the triangle
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the y coordinate of the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(
+ float v0X, float v0Y, float v0Z,
+ float v1X, float v1Y, float v1Z,
+ float v2X, float v2Y, float v2Z,
+ float pX, float pY, float pZ,
+ Vector3f result) {
+ float abX = v1X - v0X, abY = v1Y - v0Y, abZ = v1Z - v0Z;
+ float acX = v2X - v0X, acY = v2Y - v0Y, acZ = v2Z - v0Z;
+ float apX = pX - v0X, apY = pY - v0Y, apZ = pZ - v0Z;
+ float d1 = abX * apX + abY * apY + abZ * apZ;
+ float d2 = acX * apX + acY * apY + acZ * apZ;
+ if (d1 <= 0.0f && d2 <= 0.0f) {
+ result.x = v0X;
+ result.y = v0Y;
+ result.z = v0Z;
+ return POINT_ON_TRIANGLE_VERTEX_0;
+ }
+ float bpX = pX - v1X, bpY = pY - v1Y, bpZ = pZ - v1Z;
+ float d3 = abX * bpX + abY * bpY + abZ * bpZ;
+ float d4 = acX * bpX + acY * bpY + acZ * bpZ;
+ if (d3 >= 0.0f && d4 <= d3) {
+ result.x = v1X;
+ result.y = v1Y;
+ result.z = v1Z;
+ return POINT_ON_TRIANGLE_VERTEX_1;
+ }
+ float vc = d1 * d4 - d3 * d2;
+ if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
+ float v = d1 / (d1 - d3);
+ result.x = v0X + v * abX;
+ result.y = v0Y + v * abY;
+ result.z = v0Z + v * abZ;
+ return POINT_ON_TRIANGLE_EDGE_01;
+ }
+ float cpX = pX - v2X, cpY = pY - v2Y, cpZ = pZ - v2Z;
+ float d5 = abX * cpX + abY * cpY + abZ * cpZ;
+ float d6 = acX * cpX + acY * cpY + acZ * cpZ;
+ if (d6 >= 0.0f && d5 <= d6) {
+ result.x = v2X;
+ result.y = v2Y;
+ result.z = v2Z;
+ return POINT_ON_TRIANGLE_VERTEX_2;
+ }
+ float vb = d5 * d2 - d1 * d6;
+ if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
+ float w = d2 / (d2 - d6);
+ result.x = v0X + w * acX;
+ result.y = v0Y + w * acY;
+ result.z = v0Z + w * acZ;
+ return POINT_ON_TRIANGLE_EDGE_20;
+ }
+ float va = d3 * d6 - d5 * d4;
+ if (va <= 0.0f && d4 - d3 >= 0.0f && d5 - d6 >= 0.0f) {
+ float w = (d4 - d3) / (d4 - d3 + d5 - d6);
+ result.x = v1X + w * (v2X - v1X);
+ result.y = v1Y + w * (v2Y - v1Y);
+ result.z = v1Z + w * (v2Z - v1Z);
+ return POINT_ON_TRIANGLE_EDGE_12;
+ }
+ float denom = 1.0f / (va + vb + vc);
+ float v = vb * denom;
+ float w = vc * denom;
+ result.x = v0X + abX * v + acX * w;
+ result.y = v0Y + abY * v + acY * w;
+ result.z = v0Z + abZ * v + acZ * w;
+ return POINT_ON_TRIANGLE_FACE;
+ }
+
+ /**
+ * Determine the closest point on the triangle with the vertices v0
, v1
, v2
+ * between that triangle and the given point p
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @param p
+ * the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(Vector3fc v0, Vector3fc v1, Vector3fc v2, Vector3fc p, Vector3f result) {
+ return findClosestPointOnTriangle(v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), p.x(), p.y(), p.z(), result);
+ }
+
+ /**
+ * Find the point on a given rectangle, specified via three of its corners, which is closest to the specified point
+ * (pX, pY, pZ)
and store the result into res
.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.4.2 "Closest Point on 3D Rectangle to Point"
+ *
+ * @param aX
+ * the x coordinate of the first corner point of the rectangle
+ * @param aY
+ * the y coordinate of the first corner point of the rectangle
+ * @param aZ
+ * the z coordinate of the first corner point of the rectangle
+ * @param bX
+ * the x coordinate of the second corner point of the rectangle
+ * @param bY
+ * the y coordinate of the second corner point of the rectangle
+ * @param bZ
+ * the z coordinate of the second corner point of the rectangle
+ * @param cX
+ * the x coordinate of the third corner point of the rectangle
+ * @param cY
+ * the y coordinate of the third corner point of the rectangle
+ * @param cZ
+ * the z coordinate of the third corner point of the rectangle
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param res
+ * will hold the result
+ * @return res
+ */
+ public static Vector3f findClosestPointOnRectangle(
+ float aX, float aY, float aZ,
+ float bX, float bY, float bZ,
+ float cX, float cY, float cZ,
+ float pX, float pY, float pZ, Vector3f res) {
+ float abX = bX - aX, abY = bY - aY, abZ = bZ - aZ;
+ float acX = cX - aX, acY = cY - aY, acZ = cZ - aZ;
+ float dX = pX - aX, dY = pY - aY, dZ = pZ - aZ;
+ float qX = aX, qY = aY, qZ = aZ;
+ float dist = dX * abX + dY * abY + dZ * abZ;
+ float maxdist = abX * abX + abY * abY + abZ * abZ;
+ if (dist >= maxdist) {
+ qX += abX;
+ qY += abY;
+ qZ += abZ;
+ } else if (dist > 0.0f) {
+ qX += (dist / maxdist) * abX;
+ qY += (dist / maxdist) * abY;
+ qZ += (dist / maxdist) * abZ;
+ }
+ dist = dX * acX + dY * acY + dZ * acZ;
+ maxdist = acX * acX + acY * acY + acZ * acZ;
+ if (dist >= maxdist) {
+ qX += acX;
+ qY += acY;
+ qZ += acZ;
+ } else if (dist > 0.0f) {
+ qX += (dist / maxdist) * acX;
+ qY += (dist / maxdist) * acY;
+ qZ += (dist / maxdist) * acZ;
+ }
+ res.x = qX;
+ res.y = qY;
+ res.z = qZ;
+ return res;
+ }
+
+ /**
+ * Determine the point of intersection between a sphere with the given center (centerX, centerY, centerZ)
and radius
moving
+ * with the given velocity (velX, velY, velZ)
and the triangle specified via its three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
, (v2X, v2Y, v2Z)
.
+ *
+ * The vertices of the triangle must be specified in counter-clockwise winding order.
+ *
+ * An intersection is only considered if the time of intersection is smaller than the given maxT
value.
+ *
+ * Reference: Improved Collision detection and Response
+ *
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radius
+ * the radius of the sphere
+ * @param velX
+ * the x component of the velocity of the sphere
+ * @param velY
+ * the y component of the velocity of the sphere
+ * @param velZ
+ * the z component of the velocity of the sphere
+ * @param v0X
+ * the x coordinate of the first triangle vertex
+ * @param v0Y
+ * the y coordinate of the first triangle vertex
+ * @param v0Z
+ * the z coordinate of the first triangle vertex
+ * @param v1X
+ * the x coordinate of the second triangle vertex
+ * @param v1Y
+ * the y coordinate of the second triangle vertex
+ * @param v1Z
+ * the z coordinate of the second triangle vertex
+ * @param v2X
+ * the x coordinate of the third triangle vertex
+ * @param v2Y
+ * the y coordinate of the third triangle vertex
+ * @param v2Z
+ * the z coordinate of the third triangle vertex
+ * @param epsilon
+ * a small epsilon when testing spheres that move almost parallel to the triangle
+ * @param maxT
+ * the maximum intersection time
+ * @param pointAndTime
+ * iff the moving sphere and the triangle intersect, this will hold the point of intersection in the (x, y, z)
components
+ * and the time of intersection in the w
component
+ * @return {@link #POINT_ON_TRIANGLE_FACE} if the intersection point lies on the triangle's face,
+ * or {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1} or {@link #POINT_ON_TRIANGLE_VERTEX_2} if the intersection point is a vertex,
+ * or {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12} or {@link #POINT_ON_TRIANGLE_EDGE_20} if the intersection point lies on an edge;
+ * or 0
if no intersection
+ */
+ public static int intersectSweptSphereTriangle(
+ float centerX, float centerY, float centerZ, float radius, float velX, float velY, float velZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon, float maxT, Vector4f pointAndTime) {
+ float v10X = v1X - v0X;
+ float v10Y = v1Y - v0Y;
+ float v10Z = v1Z - v0Z;
+ float v20X = v2X - v0X;
+ float v20Y = v2Y - v0Y;
+ float v20Z = v2Z - v0Z;
+ // build triangle plane
+ float a = v10Y * v20Z - v20Y * v10Z;
+ float b = v10Z * v20X - v20Z * v10X;
+ float c = v10X * v20Y - v20X * v10Y;
+ float d = -(a * v0X + b * v0Y + c * v0Z);
+ float invLen = Math.invsqrt(a * a + b * b + c * c);
+ float signedDist = (a * centerX + b * centerY + c * centerZ + d) * invLen;
+ float dot = (a * velX + b * velY + c * velZ) * invLen;
+ if (dot < epsilon && dot > -epsilon)
+ return 0;
+ float pt0 = (radius - signedDist) / dot;
+ if (pt0 > maxT)
+ return 0;
+ float pt1 = (-radius - signedDist) / dot;
+ float p0X = centerX - radius * a * invLen + velX * pt0;
+ float p0Y = centerY - radius * b * invLen + velY * pt0;
+ float p0Z = centerZ - radius * c * invLen + velZ * pt0;
+ boolean insideTriangle = testPointInTriangle(p0X, p0Y, p0Z, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z);
+ if (insideTriangle) {
+ pointAndTime.x = p0X;
+ pointAndTime.y = p0Y;
+ pointAndTime.z = p0Z;
+ pointAndTime.w = pt0;
+ return POINT_ON_TRIANGLE_FACE;
+ }
+ int isect = 0;
+ float t0 = maxT;
+ float A = velX * velX + velY * velY + velZ * velZ;
+ float radius2 = radius * radius;
+ // test against v0
+ float centerV0X = centerX - v0X;
+ float centerV0Y = centerY - v0Y;
+ float centerV0Z = centerZ - v0Z;
+ float B0 = 2.0f * (velX * centerV0X + velY * centerV0Y + velZ * centerV0Z);
+ float C0 = centerV0X * centerV0X + centerV0Y * centerV0Y + centerV0Z * centerV0Z - radius2;
+ float root0 = computeLowestRoot(A, B0, C0, t0);
+ if (root0 < t0) {
+ pointAndTime.x = v0X;
+ pointAndTime.y = v0Y;
+ pointAndTime.z = v0Z;
+ pointAndTime.w = root0;
+ t0 = root0;
+ isect = POINT_ON_TRIANGLE_VERTEX_0;
+ }
+ // test against v1
+ float centerV1X = centerX - v1X;
+ float centerV1Y = centerY - v1Y;
+ float centerV1Z = centerZ - v1Z;
+ float centerV1Len = centerV1X * centerV1X + centerV1Y * centerV1Y + centerV1Z * centerV1Z;
+ float B1 = 2.0f * (velX * centerV1X + velY * centerV1Y + velZ * centerV1Z);
+ float C1 = centerV1Len - radius2;
+ float root1 = computeLowestRoot(A, B1, C1, t0);
+ if (root1 < t0) {
+ pointAndTime.x = v1X;
+ pointAndTime.y = v1Y;
+ pointAndTime.z = v1Z;
+ pointAndTime.w = root1;
+ t0 = root1;
+ isect = POINT_ON_TRIANGLE_VERTEX_1;
+ }
+ // test against v2
+ float centerV2X = centerX - v2X;
+ float centerV2Y = centerY - v2Y;
+ float centerV2Z = centerZ - v2Z;
+ float B2 = 2.0f * (velX * centerV2X + velY * centerV2Y + velZ * centerV2Z);
+ float C2 = centerV2X * centerV2X + centerV2Y * centerV2Y + centerV2Z * centerV2Z - radius2;
+ float root2 = computeLowestRoot(A, B2, C2, t0);
+ if (root2 < t0) {
+ pointAndTime.x = v2X;
+ pointAndTime.y = v2Y;
+ pointAndTime.z = v2Z;
+ pointAndTime.w = root2;
+ t0 = root2;
+ isect = POINT_ON_TRIANGLE_VERTEX_2;
+ }
+ float velLen = velX * velX + velY * velY + velZ * velZ;
+ // test against edge10
+ float len10 = v10X * v10X + v10Y * v10Y + v10Z * v10Z;
+ float baseTo0Len = centerV0X * centerV0X + centerV0Y * centerV0Y + centerV0Z * centerV0Z;
+ float v10Vel = (v10X * velX + v10Y * velY + v10Z * velZ);
+ float A10 = len10 * -velLen + v10Vel * v10Vel;
+ float v10BaseTo0 = v10X * -centerV0X + v10Y * -centerV0Y + v10Z * -centerV0Z;
+ float velBaseTo0 = velX * -centerV0X + velY * -centerV0Y + velZ * -centerV0Z;
+ float B10 = len10 * 2 * velBaseTo0 - 2 * v10Vel * v10BaseTo0;
+ float C10 = len10 * (radius2 - baseTo0Len) + v10BaseTo0 * v10BaseTo0;
+ float root10 = computeLowestRoot(A10, B10, C10, t0);
+ float f10 = (v10Vel * root10 - v10BaseTo0) / len10;
+ if (f10 >= 0.0f && f10 <= 1.0f && root10 < t0) {
+ pointAndTime.x = v0X + f10 * v10X;
+ pointAndTime.y = v0Y + f10 * v10Y;
+ pointAndTime.z = v0Z + f10 * v10Z;
+ pointAndTime.w = root10;
+ t0 = root10;
+ isect = POINT_ON_TRIANGLE_EDGE_01;
+ }
+ // test against edge20
+ float len20 = v20X * v20X + v20Y * v20Y + v20Z * v20Z;
+ float v20Vel = (v20X * velX + v20Y * velY + v20Z * velZ);
+ float A20 = len20 * -velLen + v20Vel * v20Vel;
+ float v20BaseTo0 = v20X * -centerV0X + v20Y * -centerV0Y + v20Z * -centerV0Z;
+ float B20 = len20 * 2 * velBaseTo0 - 2 * v20Vel * v20BaseTo0;
+ float C20 = len20 * (radius2 - baseTo0Len) + v20BaseTo0 * v20BaseTo0;
+ float root20 = computeLowestRoot(A20, B20, C20, t0);
+ float f20 = (v20Vel * root20 - v20BaseTo0) / len20;
+ if (f20 >= 0.0f && f20 <= 1.0f && root20 < pt1) {
+ pointAndTime.x = v0X + f20 * v20X;
+ pointAndTime.y = v0Y + f20 * v20Y;
+ pointAndTime.z = v0Z + f20 * v20Z;
+ pointAndTime.w = root20;
+ t0 = root20;
+ isect = POINT_ON_TRIANGLE_EDGE_20;
+ }
+ // test against edge21
+ float v21X = v2X - v1X;
+ float v21Y = v2Y - v1Y;
+ float v21Z = v2Z - v1Z;
+ float len21 = v21X * v21X + v21Y * v21Y + v21Z * v21Z;
+ float baseTo1Len = centerV1Len;
+ float v21Vel = (v21X * velX + v21Y * velY + v21Z * velZ);
+ float A21 = len21 * -velLen + v21Vel * v21Vel;
+ float v21BaseTo1 = v21X * -centerV1X + v21Y * -centerV1Y + v21Z * -centerV1Z;
+ float velBaseTo1 = velX * -centerV1X + velY * -centerV1Y + velZ * -centerV1Z;
+ float B21 = len21 * 2 * velBaseTo1 - 2 * v21Vel * v21BaseTo1;
+ float C21 = len21 * (radius2 - baseTo1Len) + v21BaseTo1 * v21BaseTo1;
+ float root21 = computeLowestRoot(A21, B21, C21, t0);
+ float f21 = (v21Vel * root21 - v21BaseTo1) / len21;
+ if (f21 >= 0.0f && f21 <= 1.0f && root21 < t0) {
+ pointAndTime.x = v1X + f21 * v21X;
+ pointAndTime.y = v1Y + f21 * v21Y;
+ pointAndTime.z = v1Z + f21 * v21Z;
+ pointAndTime.w = root21;
+ t0 = root21;
+ isect = POINT_ON_TRIANGLE_EDGE_12;
+ }
+ return isect;
+ }
+
+ /**
+ * Compute the lowest root for t
in the quadratic equation a*t*t + b*t + c = 0
.
+ *
+ * This is a helper method for {@link #intersectSweptSphereTriangle}
+ *
+ * @param a
+ * the quadratic factor
+ * @param b
+ * the linear factor
+ * @param c
+ * the constant
+ * @param maxR
+ * the maximum expected root
+ * @return the lowest of the two roots of the quadratic equation; or {@link Float#POSITIVE_INFINITY}
+ */
+ private static float computeLowestRoot(float a, float b, float c, float maxR) {
+ float determinant = b * b - 4.0f * a * c;
+ if (determinant < 0.0f)
+ return Float.POSITIVE_INFINITY;
+ float sqrtD = (float) Math.sqrt(determinant);
+ float r1 = (-b - sqrtD) / (2.0f * a);
+ float r2 = (-b + sqrtD) / (2.0f * a);
+ if (r1 > r2) {
+ float temp = r2;
+ r2 = r1;
+ r1 = temp;
+ }
+ if (r1 > 0.0f && r1 < maxR) {
+ return r1;
+ }
+ if (r2 > 0.0f && r2 < maxR) {
+ return r2;
+ }
+ return Float.POSITIVE_INFINITY;
+ }
+
+ /**
+ * Test whether the projection of the given point (pX, pY, pZ)
lies inside of the triangle defined by the three vertices
+ * (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * Reference: Improved Collision detection and Response
+ *
+ * @param pX
+ * the x coordinate of the point to test
+ * @param pY
+ * the y coordinate of the point to test
+ * @param pZ
+ * the z coordinate of the point to test
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @return true
if the projection of the given point lies inside of the given triangle; false
otherwise
+ */
+ public static boolean testPointInTriangle(float pX, float pY, float pZ, float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z) {
+ float e10X = v1X - v0X;
+ float e10Y = v1Y - v0Y;
+ float e10Z = v1Z - v0Z;
+ float e20X = v2X - v0X;
+ float e20Y = v2Y - v0Y;
+ float e20Z = v2Z - v0Z;
+ float a = e10X * e10X + e10Y * e10Y + e10Z * e10Z;
+ float b = e10X * e20X + e10Y * e20Y + e10Z * e20Z;
+ float c = e20X * e20X + e20Y * e20Y + e20Z * e20Z;
+ float ac_bb = a * c - b * b;
+ float vpX = pX - v0X;
+ float vpY = pY - v0Y;
+ float vpZ = pZ - v0Z;
+ float d = vpX * e10X + vpY * e10Y + vpZ * e10Z;
+ float e = vpX * e20X + vpY * e20Y + vpZ * e20Z;
+ float x = d * c - e * b;
+ float y = e * a - d * b;
+ float z = x + y - ac_bb;
+ return ((Runtime.floatToIntBits(z) & ~(Runtime.floatToIntBits(x) | Runtime.floatToIntBits(y))) & 0x8000000000000000L) != 0L;
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and normalized direction (dirX, dirY, dirZ)
+ * intersects the given sphere with center (centerX, centerY, centerZ)
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's normalized direction
+ * @param dirY
+ * the y coordinate of the ray's normalized direction
+ * @param dirZ
+ * the z coordinate of the ray's normalized direction
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the sphere
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean intersectRaySphere(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float centerX, float centerY, float centerZ, float radiusSquared, Vector2f result) {
+ float Lx = centerX - originX;
+ float Ly = centerY - originY;
+ float Lz = centerZ - originZ;
+ float tca = Lx * dirX + Ly * dirY + Lz * dirZ;
+ float d2 = Lx * Lx + Ly * Ly + Lz * Lz - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ float thc = (float) Math.sqrt(radiusSquared - d2);
+ float t0 = tca - thc;
+ float t1 = tca + thc;
+ if (t0 < t1 && t1 >= 0.0f) {
+ result.x = t0;
+ result.y = t1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and normalized direction dir
+ * intersects the sphere with the given center
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's normalized direction
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the sphere
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean intersectRaySphere(Vector3fc origin, Vector3fc dir, Vector3fc center, float radiusSquared, Vector2f result) {
+ return intersectRaySphere(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), center.x(), center.y(), center.z(), radiusSquared, result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and normalized direction (dirX, dirY, dirZ)
+ * intersects the given sphere with center (centerX, centerY, centerZ)
and square radius radiusSquared
.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's normalized direction
+ * @param dirY
+ * the y coordinate of the ray's normalized direction
+ * @param dirZ
+ * the z coordinate of the ray's normalized direction
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean testRaySphere(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float centerX, float centerY, float centerZ, float radiusSquared) {
+ float Lx = centerX - originX;
+ float Ly = centerY - originY;
+ float Lz = centerZ - originZ;
+ float tca = Lx * dirX + Ly * dirY + Lz * dirZ;
+ float d2 = Lx * Lx + Ly * Ly + Lz * Lz - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ float thc = (float) Math.sqrt(radiusSquared - d2);
+ float t0 = tca - thc;
+ float t1 = tca + thc;
+ return t0 < t1 && t1 >= 0.0f;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and normalized direction dir
+ * intersects the sphere with the given center
and square radius.
+ *
+ * This method returns true
for a ray whose origin lies inside the sphere.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's normalized direction
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the ray intersects the sphere; false
otherwise
+ */
+ public static boolean testRaySphere(Vector3fc origin, Vector3fc dir, Vector3fc center, float radiusSquared) {
+ return testRaySphere(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), center.x(), center.y(), center.z(), radiusSquared);
+ }
+
+ /**
+ * Test whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the given sphere with center (centerX, centerY, centerZ)
and square radius radiusSquared
.
+ *
+ * Reference: http://paulbourke.net/
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param centerX
+ * the x coordinate of the sphere's center
+ * @param centerY
+ * the y coordinate of the sphere's center
+ * @param centerZ
+ * the z coordinate of the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the line segment intersects the sphere; false
otherwise
+ */
+ public static boolean testLineSegmentSphere(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z,
+ float centerX, float centerY, float centerZ, float radiusSquared) {
+ float dX = p1X - p0X;
+ float dY = p1Y - p0Y;
+ float dZ = p1Z - p0Z;
+ float nom = (centerX - p0X) * dX + (centerY - p0Y) * dY + (centerZ - p0Z) * dZ;
+ float den = dX * dX + dY * dY + dZ * dZ;
+ float u = nom / den;
+ if (u < 0.0f) {
+ dX = p0X - centerX;
+ dY = p0Y - centerY;
+ dZ = p0Z - centerZ;
+ } else if (u > 1.0f) {
+ dX = p1X - centerX;
+ dY = p1Y - centerY;
+ dZ = p1Z - centerZ;
+ } else { // has to be >= 0 and <= 1
+ float pX = p0X + u * dX;
+ float pY = p0Y + u * dY;
+ float pZ = p0Z + u * dZ;
+ dX = pX - centerX;
+ dY = pY - centerY;
+ dZ = pZ - centerZ;
+ }
+ float dist = dX * dX + dY * dY + dZ * dZ;
+ return dist <= radiusSquared;
+ }
+
+ /**
+ * Test whether the line segment with the end points p0
and p1
+ * intersects the given sphere with center center
and square radius radiusSquared
.
+ *
+ * Reference: http://paulbourke.net/
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param center
+ * the sphere's center
+ * @param radiusSquared
+ * the sphere radius squared
+ * @return true
if the line segment intersects the sphere; false
otherwise
+ */
+ public static boolean testLineSegmentSphere(Vector3fc p0, Vector3fc p1, Vector3fc center, float radiusSquared) {
+ return testLineSegmentSphere(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), center.x(), center.y(), center.z(), radiusSquared);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the axis-aligned box given as its minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)
+ * @see RayAabIntersection
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * iff the ray intersects the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean intersectRayAab(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Vector2f result) {
+ float invDirX = 1.0f / dirX, invDirY = 1.0f / dirY, invDirZ = 1.0f / dirZ;
+ float tNear, tFar, tymin, tymax, tzmin, tzmax;
+ if (invDirX >= 0.0f) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0f) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return false;
+ if (invDirZ >= 0.0f) {
+ tzmin = (minZ - originZ) * invDirZ;
+ tzmax = (maxZ - originZ) * invDirZ;
+ } else {
+ tzmin = (maxZ - originZ) * invDirZ;
+ tzmax = (minZ - originZ) * invDirZ;
+ }
+ if (tNear > tzmax || tzmin > tFar)
+ return false;
+ tNear = tymin > tNear || Float.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Float.isNaN(tFar) ? tymax : tFar;
+ tNear = tzmin > tNear ? tzmin : tNear;
+ tFar = tzmax < tFar ? tzmax : tFar;
+ if (tNear < tFar && tFar >= 0.0f) {
+ result.x = tNear;
+ result.y = tFar;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the axis-aligned box specified as its minimum corner min
and maximum corner max
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection..
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAab(float, float, float, float, float, float, float, float, float, float, float, float, Vector2f)
+ * @see RayAabIntersection
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * iff the ray intersects the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean intersectRayAab(Vector3fc origin, Vector3fc dir, Vector3fc min, Vector3fc max, Vector2f result) {
+ return intersectRayAab(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), result);
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the axis-aligned box given as its minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection.
+ *
+ * This method returns true
for a line segment whose either end point lies inside the axis-aligned box.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectLineSegmentAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param minX
+ * the x coordinate of one corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of one corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of one corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the opposite corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the opposite corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the opposite corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * iff the line segment intersects the axis-aligned box
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned box; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned box; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned box; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two sides of the axis-aligned box
+ * or lies on an edge or a side of the box
+ */
+ public static int intersectLineSegmentAab(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z,
+ float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Vector2f result) {
+ float dirX = p1X - p0X, dirY = p1Y - p0Y, dirZ = p1Z - p0Z;
+ float invDirX = 1.0f / dirX, invDirY = 1.0f / dirY, invDirZ = 1.0f / dirZ;
+ float tNear, tFar, tymin, tymax, tzmin, tzmax;
+ if (invDirX >= 0.0f) {
+ tNear = (minX - p0X) * invDirX;
+ tFar = (maxX - p0X) * invDirX;
+ } else {
+ tNear = (maxX - p0X) * invDirX;
+ tFar = (minX - p0X) * invDirX;
+ }
+ if (invDirY >= 0.0f) {
+ tymin = (minY - p0Y) * invDirY;
+ tymax = (maxY - p0Y) * invDirY;
+ } else {
+ tymin = (maxY - p0Y) * invDirY;
+ tymax = (minY - p0Y) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return OUTSIDE;
+ if (invDirZ >= 0.0f) {
+ tzmin = (minZ - p0Z) * invDirZ;
+ tzmax = (maxZ - p0Z) * invDirZ;
+ } else {
+ tzmin = (maxZ - p0Z) * invDirZ;
+ tzmax = (minZ - p0Z) * invDirZ;
+ }
+ if (tNear > tzmax || tzmin > tFar)
+ return OUTSIDE;
+ tNear = tymin > tNear || Float.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Float.isNaN(tFar) ? tymax : tFar;
+ tNear = tzmin > tNear ? tzmin : tNear;
+ tFar = tzmax < tFar ? tzmax : tFar;
+ int type = OUTSIDE;
+ if (tNear <= tFar && tNear <= 1.0f && tFar >= 0.0f) {
+ if (tNear >= 0.0f && tFar > 1.0f) {
+ tFar = tNear;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar <= 1.0f) {
+ tNear = tFar;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar > 1.0f) {
+ type = INSIDE;
+ } else {
+ type = TWO_INTERSECTION;
+ }
+ result.x = tNear;
+ result.y = tFar;
+ }
+ return type;
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points p0
and p1
+ * intersects the axis-aligned box given as its minimum corner min
and maximum corner max
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + p0 * (p1 - p0) of the near and far point of intersection.
+ *
+ * This method returns true
for a line segment whose either end point lies inside the axis-aligned box.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectLineSegmentAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector2f)
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param result
+ * a vector which will hold the resulting values of the parameter
+ * t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * iff the line segment intersects the axis-aligned box
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned box; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned box; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned box; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two sides of the axis-aligned box
+ * or lies on an edge or a side of the box
+ */
+ public static int intersectLineSegmentAab(Vector3fc p0, Vector3fc p1, Vector3fc min, Vector3fc max, Vector2f result) {
+ return intersectLineSegmentAab(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the axis-aligned box given as its minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAab(Vector3fc, Vector3fc, Vector3fc, Vector3fc)
+ * @see RayAabIntersection
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean testRayAab(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ float invDirX = 1.0f / dirX, invDirY = 1.0f / dirY, invDirZ = 1.0f / dirZ;
+ float tNear, tFar, tymin, tymax, tzmin, tzmax;
+ if (invDirX >= 0.0f) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0f) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return false;
+ if (invDirZ >= 0.0f) {
+ tzmin = (minZ - originZ) * invDirZ;
+ tzmax = (maxZ - originZ) * invDirZ;
+ } else {
+ tzmin = (maxZ - originZ) * invDirZ;
+ tzmax = (minZ - originZ) * invDirZ;
+ }
+ if (tNear > tzmax || tzmin > tFar)
+ return false;
+ tNear = tymin > tNear || Float.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Float.isNaN(tFar) ? tymax : tFar;
+ tNear = tzmin > tNear ? tzmin : tNear;
+ tFar = tzmax < tFar ? tzmax : tFar;
+ return tNear < tFar && tFar >= 0.0f;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the axis-aligned box specified as its minimum corner min
and maximum corner max
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned box.
+ *
+ * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAab(float, float, float, float, float, float, float, float, float, float, float, float)
+ * @see RayAabIntersection
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @return true
if the given ray intersects the axis-aligned box; false
otherwise
+ */
+ public static boolean testRayAab(Vector3fc origin, Vector3fc dir, Vector3fc min, Vector3fc max) {
+ return testRayAab(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), min.x(), min.y(), min.z(), max.x(), max.y(), max.z());
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the frontface of the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #testRayTriangleFront(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3fc, float)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangleFront(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon) {
+ float edge1X = v1X - v0X;
+ float edge1Y = v1Y - v0Y;
+ float edge1Z = v1Z - v0Z;
+ float edge2X = v2X - v0X;
+ float edge2Y = v2Y - v0Y;
+ float edge2Z = v2Z - v0Z;
+ float pvecX = dirY * edge2Z - dirZ * edge2Y;
+ float pvecY = dirZ * edge2X - dirX * edge2Z;
+ float pvecZ = dirX * edge2Y - dirY * edge2X;
+ float det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det < epsilon)
+ return false;
+ float tvecX = originX - v0X;
+ float tvecY = originY - v0Y;
+ float tvecZ = originZ - v0Z;
+ float u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ);
+ if (u < 0.0f || u > det)
+ return false;
+ float qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ float qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ float qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ float v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ);
+ if (v < 0.0f || u + v > det)
+ return false;
+ float invDet = 1.0f / det;
+ float t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t >= epsilon;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and the given dir
intersects the frontface of the triangle consisting of the three vertices
+ * v0
, v1
and v2
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #testRayTriangleFront(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangleFront(Vector3fc origin, Vector3fc dir, Vector3fc v0, Vector3fc v1, Vector3fc v2, float epsilon) {
+ return testRayTriangleFront(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #testRayTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3fc, float)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangle(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon) {
+ float edge1X = v1X - v0X;
+ float edge1Y = v1Y - v0Y;
+ float edge1Z = v1Z - v0Z;
+ float edge2X = v2X - v0X;
+ float edge2Y = v2Y - v0Y;
+ float edge2Z = v2Z - v0Z;
+ float pvecX = dirY * edge2Z - dirZ * edge2Y;
+ float pvecY = dirZ * edge2X - dirX * edge2Z;
+ float pvecZ = dirX * edge2Y - dirY * edge2X;
+ float det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det > -epsilon && det < epsilon)
+ return false;
+ float tvecX = originX - v0X;
+ float tvecY = originY - v0Y;
+ float tvecZ = originZ - v0Z;
+ float invDet = 1.0f / det;
+ float u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet;
+ if (u < 0.0f || u > 1.0f)
+ return false;
+ float qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ float qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ float qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ float v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ) * invDet;
+ if (v < 0.0f || u + v > 1.0f)
+ return false;
+ float t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t >= epsilon;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and the given dir
intersects the frontface of the triangle consisting of the three vertices
+ * v0
, v1
and v2
.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #testRayTriangle(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return true
if the given ray intersects the frontface of the triangle; false
otherwise
+ */
+ public static boolean testRayTriangle(Vector3fc origin, Vector3fc dir, Vector3fc v0, Vector3fc v1, Vector3fc v2, float epsilon) {
+ return testRayTriangle(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Determine whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the frontface of the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
+ * and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #testRayTriangleFront(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3fc, float)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the frontface of the triangle; -1.0
otherwise
+ */
+ public static float intersectRayTriangleFront(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon) {
+ float edge1X = v1X - v0X;
+ float edge1Y = v1Y - v0Y;
+ float edge1Z = v1Z - v0Z;
+ float edge2X = v2X - v0X;
+ float edge2Y = v2Y - v0Y;
+ float edge2Z = v2Z - v0Z;
+ float pvecX = dirY * edge2Z - dirZ * edge2Y;
+ float pvecY = dirZ * edge2X - dirX * edge2Z;
+ float pvecZ = dirX * edge2Y - dirY * edge2X;
+ float det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det <= epsilon)
+ return -1.0f;
+ float tvecX = originX - v0X;
+ float tvecY = originY - v0Y;
+ float tvecZ = originZ - v0Z;
+ float u = tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ;
+ if (u < 0.0f || u > det)
+ return -1.0f;
+ float qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ float qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ float qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ float v = dirX * qvecX + dirY * qvecY + dirZ * qvecZ;
+ if (v < 0.0f || u + v > det)
+ return -1.0f;
+ float invDet = 1.0f / det;
+ float t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t;
+ }
+
+ /**
+ * Determine whether the ray with the given origin
and the given dir
intersects the frontface of the triangle consisting of the three vertices
+ * v0
, v1
and v2
and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test implements backface culling, that is, it will return false
when the triangle is in clockwise
+ * winding order assuming a right-handed coordinate system when seen along the ray's direction, even if the ray intersects the triangle.
+ * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings.
+ *
+ * @see #intersectRayTriangleFront(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the frontface of the triangle; -1.0
otherwise
+ */
+ public static float intersectRayTriangleFront(Vector3fc origin, Vector3fc dir, Vector3fc v0, Vector3fc v1, Vector3fc v2, float epsilon) {
+ return intersectRayTriangleFront(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Determine whether the given ray with the origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
+ * and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #testRayTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3fc, float)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param originZ
+ * the z coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param dirZ
+ * the z coordinate of the ray's direction
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the triangle; -1.0
otherwise
+ */
+ public static float intersectRayTriangle(float originX, float originY, float originZ, float dirX, float dirY, float dirZ,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon) {
+ float edge1X = v1X - v0X;
+ float edge1Y = v1Y - v0Y;
+ float edge1Z = v1Z - v0Z;
+ float edge2X = v2X - v0X;
+ float edge2Y = v2Y - v0Y;
+ float edge2Z = v2Z - v0Z;
+ float pvecX = dirY * edge2Z - dirZ * edge2Y;
+ float pvecY = dirZ * edge2X - dirX * edge2Z;
+ float pvecZ = dirX * edge2Y - dirY * edge2X;
+ float det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det > -epsilon && det < epsilon)
+ return -1.0f;
+ float tvecX = originX - v0X;
+ float tvecY = originY - v0Y;
+ float tvecZ = originZ - v0Z;
+ float invDet = 1.0f / det;
+ float u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet;
+ if (u < 0.0f || u > 1.0f)
+ return -1.0f;
+ float qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ float qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ float qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ float v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ) * invDet;
+ if (v < 0.0f || u + v > 1.0f)
+ return -1.0f;
+ float t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t;
+ }
+
+ /**
+ * Determine whether the ray with the given origin
and the given dir
intersects the triangle consisting of the three vertices
+ * v0
, v1
and v2
and return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection.
+ *
+ * This is an implementation of the
+ * Fast, Minimum Storage Ray/Triangle Intersection method.
+ *
+ * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle.
+ *
+ * @see #intersectRayTriangle(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing rays that are almost parallel to the triangle
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the point of intersection
+ * if the ray intersects the triangle; -1.0
otherwise
+ */
+ public static float intersectRayTriangle(Vector3fc origin, Vector3fc dir, Vector3fc v0, Vector3fc v1, Vector3fc v2, float epsilon) {
+ return intersectRayTriangle(origin.x(), origin.y(), origin.z(), dir.x(), dir.y(), dir.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Test whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #testLineSegmentTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3fc, float)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean testLineSegmentTriangle(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon) {
+ float dirX = p1X - p0X;
+ float dirY = p1Y - p0Y;
+ float dirZ = p1Z - p0Z;
+ float t = intersectRayTriangle(p0X, p0Y, p0Z, dirX, dirY, dirZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, epsilon);
+ return t >= 0.0f && t <= 1.0f;
+ }
+
+ /**
+ * Test whether the line segment with the end points p0
and p1
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #testLineSegmentTriangle(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean testLineSegmentTriangle(Vector3fc p0, Vector3fc p1, Vector3fc v0, Vector3fc v1, Vector3fc v2, float epsilon) {
+ return testLineSegmentTriangle(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon);
+ }
+
+ /**
+ * Determine whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points,
+ * and return the point of intersection.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #intersectLineSegmentTriangle(Vector3fc, Vector3fc, Vector3fc, Vector3fc, Vector3fc, float, Vector3f)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param v0X
+ * the x coordinate of the first vertex
+ * @param v0Y
+ * the y coordinate of the first vertex
+ * @param v0Z
+ * the z coordinate of the first vertex
+ * @param v1X
+ * the x coordinate of the second vertex
+ * @param v1Y
+ * the y coordinate of the second vertex
+ * @param v1Z
+ * the z coordinate of the second vertex
+ * @param v2X
+ * the x coordinate of the third vertex
+ * @param v2Y
+ * the y coordinate of the third vertex
+ * @param v2Z
+ * the z coordinate of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @param intersectionPoint
+ * the point of intersection
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean intersectLineSegmentTriangle(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z,
+ float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y, float v2Z,
+ float epsilon, Vector3f intersectionPoint) {
+ float dirX = p1X - p0X;
+ float dirY = p1Y - p0Y;
+ float dirZ = p1Z - p0Z;
+ float t = intersectRayTriangle(p0X, p0Y, p0Z, dirX, dirY, dirZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, epsilon);
+ if (t >= 0.0f && t <= 1.0f) {
+ intersectionPoint.x = p0X + dirX * t;
+ intersectionPoint.y = p0Y + dirY * t;
+ intersectionPoint.z = p0Z + dirZ * t;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Determine whether the line segment with the end points p0
and p1
+ * intersects the triangle consisting of the three vertices (v0X, v0Y, v0Z)
, (v1X, v1Y, v1Z)
and (v2X, v2Y, v2Z)
,
+ * regardless of the winding order of the triangle or the direction of the line segment between its two end points,
+ * and return the point of intersection.
+ *
+ * Reference:
+ * Fast, Minimum Storage Ray/Triangle Intersection
+ *
+ * @see #intersectLineSegmentTriangle(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, Vector3f)
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param v0
+ * the position of the first vertex
+ * @param v1
+ * the position of the second vertex
+ * @param v2
+ * the position of the third vertex
+ * @param epsilon
+ * a small epsilon when testing line segments that are almost parallel to the triangle
+ * @param intersectionPoint
+ * the point of intersection
+ * @return true
if the given line segment intersects the triangle; false
otherwise
+ */
+ public static boolean intersectLineSegmentTriangle(Vector3fc p0, Vector3fc p1, Vector3fc v0, Vector3fc v1, Vector3fc v2, float epsilon, Vector3f intersectionPoint) {
+ return intersectLineSegmentTriangle(p0.x(), p0.y(), p0.z(), p1.x(), p1.y(), p1.z(), v0.x(), v0.y(), v0.z(), v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z(), epsilon, intersectionPoint);
+ }
+
+ /**
+ * Determine whether the line segment with the end points (p0X, p0Y, p0Z)
and (p1X, p1Y, p1Z)
+ * intersects the plane given as the general plane equation a*x + b*y + c*z + d = 0,
+ * and return the point of intersection.
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p0Z
+ * the z coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param p1Z
+ * the z coordinate of the line segment's second end point
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param intersectionPoint
+ * the point of intersection
+ * @return true
if the given line segment intersects the plane; false
otherwise
+ */
+ public static boolean intersectLineSegmentPlane(float p0X, float p0Y, float p0Z, float p1X, float p1Y, float p1Z,
+ float a, float b, float c, float d, Vector3f intersectionPoint) {
+ float dirX = p1X - p0X;
+ float dirY = p1Y - p0Y;
+ float dirZ = p1Z - p0Z;
+ float denom = a * dirX + b * dirY + c * dirZ;
+ float t = -(a * p0X + b * p0Y + c * p0Z + d) / denom;
+ if (t >= 0.0f && t <= 1.0f) {
+ intersectionPoint.x = p0X + t * dirX;
+ intersectionPoint.y = p0Y + t * dirY;
+ intersectionPoint.z = p0Z + t * dirZ;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the line with the general line equation a*x + b*y + c = 0 intersects the circle with center
+ * (centerX, centerY)
and radius
.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the line equation
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radius
+ * the radius of the circle
+ * @return true
iff the line intersects the circle; false
otherwise
+ */
+ public static boolean testLineCircle(float a, float b, float c, float centerX, float centerY, float radius) {
+ float denom = (float) Math.sqrt(a * a + b * b);
+ float dist = (a * centerX + b * centerY + c) / denom;
+ return -radius <= dist && dist <= radius;
+ }
+
+ /**
+ * Test whether the line with the general line equation a*x + b*y + c = 0 intersects the circle with center
+ * (centerX, centerY)
and radius
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the line equation
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radius
+ * the radius of the circle
+ * @param intersectionCenterAndHL
+ * will hold the center of the line segment of intersection in the (x, y)
components and the half-length in the z component
+ * @return true
iff the line intersects the circle; false
otherwise
+ */
+ public static boolean intersectLineCircle(float a, float b, float c, float centerX, float centerY, float radius, Vector3f intersectionCenterAndHL) {
+ float invDenom = Math.invsqrt(a * a + b * b);
+ float dist = (a * centerX + b * centerY + c) * invDenom;
+ if (-radius <= dist && dist <= radius) {
+ intersectionCenterAndHL.x = centerX + dist * a * invDenom;
+ intersectionCenterAndHL.y = centerY + dist * b * invDenom;
+ intersectionCenterAndHL.z = (float) Math.sqrt(radius * radius - dist * dist);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the line defined by the two points (x0, y0)
and (x1, y1)
intersects the circle with center
+ * (centerX, centerY)
and radius
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * Reference: http://math.stackexchange.com
+ *
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radius
+ * the radius of the circle
+ * @param intersectionCenterAndHL
+ * will hold the center of the line segment of intersection in the (x, y)
components and the half-length in the z component
+ * @return true
iff the line intersects the circle; false
otherwise
+ */
+ public static boolean intersectLineCircle(float x0, float y0, float x1, float y1, float centerX, float centerY, float radius, Vector3f intersectionCenterAndHL) {
+ // Build general line equation from two points and use the other method
+ return intersectLineCircle(y0 - y1, x1 - x0, (x0 - x1) * y0 + (y1 - y0) * x0, centerX, centerY, radius, intersectionCenterAndHL);
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minX, minY)
and maximum corner (maxX, maxY)
+ * intersects the line with the general equation a*x + b*y + c = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the plane equation
+ * @return true
iff the axis-aligned rectangle intersects the line; false
otherwise
+ */
+ public static boolean testAarLine(float minX, float minY, float maxX, float maxY, float a, float b, float c) {
+ float pX, pY, nX, nY;
+ if (a > 0.0f) {
+ pX = maxX;
+ nX = minX;
+ } else {
+ pX = minX;
+ nX = maxX;
+ }
+ if (b > 0.0f) {
+ pY = maxY;
+ nY = minY;
+ } else {
+ pY = minY;
+ nY = maxY;
+ }
+ float distN = c + a * nX + b * nY;
+ float distP = c + a * pX + b * pY;
+ return distN <= 0.0f && distP >= 0.0f;
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner min
and maximum corner max
+ * intersects the line with the general equation a*x + b*y + c = 0.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param a
+ * the x factor in the line equation
+ * @param b
+ * the y factor in the line equation
+ * @param c
+ * the constant in the line equation
+ * @return true
iff the axis-aligned rectangle intersects the line; false
otherwise
+ */
+ public static boolean testAarLine(Vector2fc min, Vector2fc max, float a, float b, float c) {
+ return testAarLine(min.x(), min.y(), max.x(), max.y(), a, b, c);
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minX, minY)
and maximum corner (maxX, maxY)
+ * intersects the line defined by the two points (x0, y0)
and (x1, y1)
.
+ *
+ * Reference: http://www.lighthouse3d.com ("Geometric Approach - Testing Boxes II")
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @return true
iff the axis-aligned rectangle intersects the line; false
otherwise
+ */
+ public static boolean testAarLine(float minX, float minY, float maxX, float maxY, float x0, float y0, float x1, float y1) {
+ float a = y0 - y1;
+ float b = x1 - x0;
+ float c = -b * y0 - a * x0;
+ return testAarLine(minX, minY, maxX, maxY, a, b, c);
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minXA, minYA)
and maximum corner (maxXA, maxYA)
+ * intersects the axis-aligned rectangle with minimum corner (minXB, minYB)
and maximum corner (maxXB, maxYB)
.
+ *
+ * @param minXA
+ * the x coordinate of the minimum corner of the first axis-aligned rectangle
+ * @param minYA
+ * the y coordinate of the minimum corner of the first axis-aligned rectangle
+ * @param maxXA
+ * the x coordinate of the maximum corner of the first axis-aligned rectangle
+ * @param maxYA
+ * the y coordinate of the maximum corner of the first axis-aligned rectangle
+ * @param minXB
+ * the x coordinate of the minimum corner of the second axis-aligned rectangle
+ * @param minYB
+ * the y coordinate of the minimum corner of the second axis-aligned rectangle
+ * @param maxXB
+ * the x coordinate of the maximum corner of the second axis-aligned rectangle
+ * @param maxYB
+ * the y coordinate of the maximum corner of the second axis-aligned rectangle
+ * @return true
iff both axis-aligned rectangles intersect; false
otherwise
+ */
+ public static boolean testAarAar(float minXA, float minYA, float maxXA, float maxYA, float minXB, float minYB, float maxXB, float maxYB) {
+ return maxXA >= minXB && maxYA >= minYB && minXA <= maxXB && minYA <= maxYB;
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner minA
and maximum corner maxA
+ * intersects the axis-aligned rectangle with minimum corner minB
and maximum corner maxB
.
+ *
+ * @param minA
+ * the minimum corner of the first axis-aligned rectangle
+ * @param maxA
+ * the maximum corner of the first axis-aligned rectangle
+ * @param minB
+ * the minimum corner of the second axis-aligned rectangle
+ * @param maxB
+ * the maximum corner of the second axis-aligned rectangle
+ * @return true
iff both axis-aligned rectangles intersect; false
otherwise
+ */
+ public static boolean testAarAar(Vector2fc minA, Vector2fc maxA, Vector2fc minB, Vector2fc maxB) {
+ return testAarAar(minA.x(), minA.y(), maxA.x(), maxA.y(), minB.x(), minB.y(), maxB.x(), maxB.y());
+ }
+
+ /**
+ * Test whether a given circle with center (aX, aY)
and radius aR
and travelled distance vector (maX, maY)
+ * intersects a given static circle with center (bX, bY)
and radius bR
.
+ *
+ * Note that the case of two moving circles can always be reduced to this case by expressing the moved distance of one of the circles relative
+ * to the other.
+ *
+ * Reference: https://www.gamasutra.com
+ *
+ * @param aX
+ * the x coordinate of the first circle's center
+ * @param aY
+ * the y coordinate of the first circle's center
+ * @param maX
+ * the x coordinate of the first circle's travelled distance vector
+ * @param maY
+ * the y coordinate of the first circle's travelled distance vector
+ * @param aR
+ * the radius of the first circle
+ * @param bX
+ * the x coordinate of the second circle's center
+ * @param bY
+ * the y coordinate of the second circle's center
+ * @param bR
+ * the radius of the second circle
+ * @return true
if both circle intersect; false
otherwise
+ */
+ public static boolean testMovingCircleCircle(float aX, float aY, float maX, float maY, float aR, float bX, float bY, float bR) {
+ float aRbR = aR + bR;
+ float dist = (float) Math.sqrt((aX - bX) * (aX - bX) + (aY - bY) * (aY - bY)) - aRbR;
+ float mLen = (float) Math.sqrt(maX * maX + maY * maY);
+ if (mLen < dist)
+ return false;
+ float invMLen = 1.0f / mLen;
+ float nX = maX * invMLen;
+ float nY = maY * invMLen;
+ float cX = bX - aX;
+ float cY = bY - aY;
+ float nDotC = nX * cX + nY * cY;
+ if (nDotC <= 0.0f)
+ return false;
+ float cLen = (float) Math.sqrt(cX * cX + cY * cY);
+ float cLenNdotC = cLen * cLen - nDotC * nDotC;
+ float aRbR2 = aRbR * aRbR;
+ if (cLenNdotC >= aRbR2)
+ return false;
+ float t = aRbR2 - cLenNdotC;
+ if (t < 0.0f)
+ return false;
+ float distance = nDotC - (float) Math.sqrt(t);
+ float mag = mLen;
+ if (mag < distance)
+ return false;
+ return true;
+ }
+
+ /**
+ * Test whether a given circle with center centerA
and radius aR
and travelled distance vector moveA
+ * intersects a given static circle with center centerB
and radius bR
.
+ *
+ * Note that the case of two moving circles can always be reduced to this case by expressing the moved distance of one of the circles relative
+ * to the other.
+ *
+ * Reference: https://www.gamasutra.com
+ *
+ * @param centerA
+ * the coordinates of the first circle's center
+ * @param moveA
+ * the coordinates of the first circle's travelled distance vector
+ * @param aR
+ * the radius of the first circle
+ * @param centerB
+ * the coordinates of the second circle's center
+ * @param bR
+ * the radius of the second circle
+ * @return true
if both circle intersect; false
otherwise
+ */
+ public static boolean testMovingCircleCircle(Vector2f centerA, Vector2f moveA, float aR, Vector2f centerB, float bR) {
+ return testMovingCircleCircle(centerA.x, centerA.y, moveA.x, moveA.y, aR, centerB.x, centerB.y, bR);
+ }
+
+ /**
+ * Test whether the one circle with center (aX, aY)
and square radius radiusSquaredA
intersects the other
+ * circle with center (bX, bY)
and square radius radiusSquaredB
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * This method returns false
when one circle contains the other circle.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param aX
+ * the x coordinate of the first circle's center
+ * @param aY
+ * the y coordinate of the first circle's center
+ * @param radiusSquaredA
+ * the square of the first circle's radius
+ * @param bX
+ * the x coordinate of the second circle's center
+ * @param bY
+ * the y coordinate of the second circle's center
+ * @param radiusSquaredB
+ * the square of the second circle's radius
+ * @param intersectionCenterAndHL
+ * will hold the center of the circle of intersection in the (x, y, z)
components and the radius in the w component
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean intersectCircleCircle(float aX, float aY, float radiusSquaredA, float bX, float bY, float radiusSquaredB, Vector3f intersectionCenterAndHL) {
+ float dX = bX - aX, dY = bY - aY;
+ float distSquared = dX * dX + dY * dY;
+ float h = 0.5f + (radiusSquaredA - radiusSquaredB) / distSquared;
+ float r_i = (float) Math.sqrt(radiusSquaredA - h * h * distSquared);
+ if (r_i >= 0.0f) {
+ intersectionCenterAndHL.x = aX + h * dX;
+ intersectionCenterAndHL.y = aY + h * dY;
+ intersectionCenterAndHL.z = r_i;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the one circle with center centerA
and square radius radiusSquaredA
intersects the other
+ * circle with center centerB
and square radius radiusSquaredB
, and store the center of the line segment of
+ * intersection in the (x, y)
components of the supplied vector and the half-length of that line segment in the z component.
+ *
+ * This method returns false
when one circle contains the other circle.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first circle's center
+ * @param radiusSquaredA
+ * the square of the first circle's radius
+ * @param centerB
+ * the second circle's center
+ * @param radiusSquaredB
+ * the square of the second circle's radius
+ * @param intersectionCenterAndHL
+ * will hold the center of the line segment of intersection in the (x, y)
components and the half-length in the z component
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean intersectCircleCircle(Vector2fc centerA, float radiusSquaredA, Vector2fc centerB, float radiusSquaredB, Vector3f intersectionCenterAndHL) {
+ return intersectCircleCircle(centerA.x(), centerA.y(), radiusSquaredA, centerB.x(), centerB.y(), radiusSquaredB, intersectionCenterAndHL);
+ }
+
+ /**
+ * Test whether the one circle with center (aX, aY)
and radius rA
intersects the other circle with center (bX, bY)
and radius rB
.
+ *
+ * This method returns true
when one circle contains the other circle.
+ *
+ * Reference: http://math.stackexchange.com/
+ *
+ * @param aX
+ * the x coordinate of the first circle's center
+ * @param aY
+ * the y coordinate of the first circle's center
+ * @param rA
+ * the square of the first circle's radius
+ * @param bX
+ * the x coordinate of the second circle's center
+ * @param bY
+ * the y coordinate of the second circle's center
+ * @param rB
+ * the square of the second circle's radius
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean testCircleCircle(float aX, float aY, float rA, float bX, float bY, float rB) {
+ float d = (aX - bX) * (aX - bX) + (aY - bY) * (aY - bY);
+ return d <= (rA + rB) * (rA + rB);
+ }
+
+ /**
+ * Test whether the one circle with center centerA
and square radius radiusSquaredA
intersects the other
+ * circle with center centerB
and square radius radiusSquaredB
.
+ *
+ * This method returns true
when one circle contains the other circle.
+ *
+ * Reference: http://gamedev.stackexchange.com
+ *
+ * @param centerA
+ * the first circle's center
+ * @param radiusSquaredA
+ * the square of the first circle's radius
+ * @param centerB
+ * the second circle's center
+ * @param radiusSquaredB
+ * the square of the second circle's radius
+ * @return true
iff both circles intersect; false
otherwise
+ */
+ public static boolean testCircleCircle(Vector2fc centerA, float radiusSquaredA, Vector2fc centerB, float radiusSquaredB) {
+ return testCircleCircle(centerA.x(), centerA.y(), radiusSquaredA, centerB.x(), centerB.y(), radiusSquaredB);
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY)
to the line specified via its general plane equation
+ * a*x + b*y + c = 0.
+ *
+ * Reference: http://mathworld.wolfram.com
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the constant in the plane equation
+ * @return the distance between the point and the line
+ */
+ public static float distancePointLine(float pointX, float pointY, float a, float b, float c) {
+ float denom = (float) Math.sqrt(a * a + b * b);
+ return (a * pointX + b * pointY + c) / denom;
+ }
+
+ /**
+ * Determine the signed distance of the given point (pointX, pointY)
to the line defined by the two points (x0, y0)
and (x1, y1)
.
+ *
+ * Reference: http://mathworld.wolfram.com
+ *
+ * @param pointX
+ * the x coordinate of the point
+ * @param pointY
+ * the y coordinate of the point
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @return the distance between the point and the line
+ */
+ public static float distancePointLine(float pointX, float pointY, float x0, float y0, float x1, float y1) {
+ float dx = x1 - x0;
+ float dy = y1 - y0;
+ float denom = (float) Math.sqrt(dx * dx + dy * dy);
+ return (dx * (y0 - pointY) - (x0 - pointX) * dy) / denom;
+ }
+
+ /**
+ * Compute the distance of the given point (pX, pY, pZ)
to the line defined by the two points (x0, y0, z0)
and (x1, y1, z1)
.
+ *
+ * Reference: http://mathworld.wolfram.com
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param pZ
+ * the z coordinate of the point
+ * @param x0
+ * the x coordinate of the first point on the line
+ * @param y0
+ * the y coordinate of the first point on the line
+ * @param z0
+ * the z coordinate of the first point on the line
+ * @param x1
+ * the x coordinate of the second point on the line
+ * @param y1
+ * the y coordinate of the second point on the line
+ * @param z1
+ * the z coordinate of the second point on the line
+ * @return the distance between the point and the line
+ */
+ public static float distancePointLine(float pX, float pY, float pZ,
+ float x0, float y0, float z0, float x1, float y1, float z1) {
+ float d21x = x1 - x0, d21y = y1 - y0, d21z = z1 - z0;
+ float d10x = x0 - pX, d10y = y0 - pY, d10z = z0 - pZ;
+ float cx = d21y * d10z - d21z * d10y, cy = d21z * d10x - d21x * d10z, cz = d21x * d10y - d21y * d10x;
+ return (float) Math.sqrt((cx*cx + cy*cy + cz*cz) / (d21x*d21x + d21y*d21y + d21z*d21z));
+ }
+
+ /**
+ * Test whether the ray with given origin (originX, originY)
and direction (dirX, dirY)
intersects the line
+ * containing the given point (pointX, pointY)
and having the normal (normalX, normalY)
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the line, because it is either parallel to the line or its direction points
+ * away from the line or the ray's origin is on the negative side of the line (i.e. the line's normal points away from the ray's origin).
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param pointX
+ * the x coordinate of a point on the line
+ * @param pointY
+ * the y coordinate of a point on the line
+ * @param normalX
+ * the x coordinate of the line's normal
+ * @param normalY
+ * the y coordinate of the line's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the line
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line; -1.0
otherwise
+ */
+ public static float intersectRayLine(float originX, float originY, float dirX, float dirY, float pointX, float pointY, float normalX, float normalY, float epsilon) {
+ float denom = normalX * dirX + normalY * dirY;
+ if (denom < epsilon) {
+ float t = ((pointX - originX) * normalX + (pointY - originY) * normalY) / denom;
+ if (t >= 0.0f)
+ return t;
+ }
+ return -1.0f;
+ }
+
+ /**
+ * Test whether the ray with given origin
and direction dir
intersects the line
+ * containing the given point
and having the given normal
, and return the
+ * value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point.
+ *
+ * This method returns -1.0
if the ray does not intersect the line, because it is either parallel to the line or its direction points
+ * away from the line or the ray's origin is on the negative side of the line (i.e. the line's normal points away from the ray's origin).
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param point
+ * a point on the line
+ * @param normal
+ * the line's normal
+ * @param epsilon
+ * some small epsilon for when the ray is parallel to the line
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line; -1.0
otherwise
+ */
+ public static float intersectRayLine(Vector2fc origin, Vector2fc dir, Vector2fc point, Vector2fc normal, float epsilon) {
+ return intersectRayLine(origin.x(), origin.y(), dir.x(), dir.y(), point.x(), point.y(), normal.x(), normal.y(), epsilon);
+ }
+
+ /**
+ * Determine whether the ray with given origin (originX, originY)
and direction (dirX, dirY)
intersects the undirected line segment
+ * given by the two end points (aX, bY)
and (bX, bY)
, and return the value of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the intersection point, if any.
+ *
+ * This method returns -1.0
if the ray does not intersect the line segment.
+ *
+ * @see #intersectRayLineSegment(Vector2fc, Vector2fc, Vector2fc, Vector2fc)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param aX
+ * the x coordinate of the line segment's first end point
+ * @param aY
+ * the y coordinate of the line segment's first end point
+ * @param bX
+ * the x coordinate of the line segment's second end point
+ * @param bY
+ * the y coordinate of the line segment's second end point
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line segment; -1.0
otherwise
+ */
+ public static float intersectRayLineSegment(float originX, float originY, float dirX, float dirY, float aX, float aY, float bX, float bY) {
+ float v1X = originX - aX;
+ float v1Y = originY - aY;
+ float v2X = bX - aX;
+ float v2Y = bY - aY;
+ float invV23 = 1.0f / (v2Y * dirX - v2X * dirY);
+ float t1 = (v2X * v1Y - v2Y * v1X) * invV23;
+ float t2 = (v1Y * dirX - v1X * dirY) * invV23;
+ if (t1 >= 0.0f && t2 >= 0.0f && t2 <= 1.0f)
+ return t1;
+ return -1.0f;
+ }
+
+ /**
+ * Determine whether the ray with given origin
and direction dir
intersects the undirected line segment
+ * given by the two end points a
and b
, and return the value of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the intersection point, if any.
+ *
+ * This method returns -1.0
if the ray does not intersect the line segment.
+ *
+ * @see #intersectRayLineSegment(float, float, float, float, float, float, float, float)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param a
+ * the line segment's first end point
+ * @param b
+ * the line segment's second end point
+ * @return the value of the parameter t in the ray equation p(t) = origin + t * dir of the intersection point, if the ray
+ * intersects the line segment; -1.0
otherwise
+ */
+ public static float intersectRayLineSegment(Vector2fc origin, Vector2fc dir, Vector2fc a, Vector2fc b) {
+ return intersectRayLineSegment(origin.x(), origin.y(), dir.x(), dir.y(), a.x(), a.y(), b.x(), b.y());
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner (minX, minY)
and maximum corner (maxX, maxY)
+ * intersects the circle with the given center (centerX, centerY)
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the square of the circle's radius
+ * @return true
iff the axis-aligned rectangle intersects the circle; false
otherwise
+ */
+ public static boolean testAarCircle(float minX, float minY, float maxX, float maxY, float centerX, float centerY, float radiusSquared) {
+ float radius2 = radiusSquared;
+ if (centerX < minX) {
+ float d = (centerX - minX);
+ radius2 -= d * d;
+ } else if (centerX > maxX) {
+ float d = (centerX - maxX);
+ radius2 -= d * d;
+ }
+ if (centerY < minY) {
+ float d = (centerY - minY);
+ radius2 -= d * d;
+ } else if (centerY > maxY) {
+ float d = (centerY - maxY);
+ radius2 -= d * d;
+ }
+ return radius2 >= 0.0f;
+ }
+
+ /**
+ * Test whether the axis-aligned rectangle with minimum corner min
and maximum corner max
+ * intersects the circle with the given center
and square radius radiusSquared
.
+ *
+ * Reference: http://stackoverflow.com
+ *
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the squared of the circle's radius
+ * @return true
iff the axis-aligned rectangle intersects the circle; false
otherwise
+ */
+ public static boolean testAarCircle(Vector2fc min, Vector2fc max, Vector2fc center, float radiusSquared) {
+ return testAarCircle(min.x(), min.y(), max.x(), max.y(), center.x(), center.y(), radiusSquared);
+ }
+
+ /**
+ * Determine the closest point on the triangle with the given vertices (v0X, v0Y)
, (v1X, v1Y)
, (v2X, v2Y)
+ * between that triangle and the given point (pX, pY)
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(float v0X, float v0Y, float v1X, float v1Y, float v2X, float v2Y, float pX, float pY, Vector2f result) {
+ float abX = v1X - v0X, abY = v1Y - v0Y;
+ float acX = v2X - v0X, acY = v2Y - v0Y;
+ float apX = pX - v0X, apY = pY - v0Y;
+ float d1 = abX * apX + abY * apY;
+ float d2 = acX * apX + acY * apY;
+ if (d1 <= 0.0f && d2 <= 0.0f) {
+ result.x = v0X;
+ result.y = v0Y;
+ return POINT_ON_TRIANGLE_VERTEX_0;
+ }
+ float bpX = pX - v1X, bpY = pY - v1Y;
+ float d3 = abX * bpX + abY * bpY;
+ float d4 = acX * bpX + acY * bpY;
+ if (d3 >= 0.0f && d4 <= d3) {
+ result.x = v1X;
+ result.y = v1Y;
+ return POINT_ON_TRIANGLE_VERTEX_1;
+ }
+ float vc = d1 * d4 - d3 * d2;
+ if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
+ float v = d1 / (d1 - d3);
+ result.x = v0X + v * abX;
+ result.y = v0Y + v * abY;
+ return POINT_ON_TRIANGLE_EDGE_01;
+ }
+ float cpX = pX - v2X, cpY = pY - v2Y;
+ float d5 = abX * cpX + abY * cpY;
+ float d6 = acX * cpX + acY * cpY;
+ if (d6 >= 0.0f && d5 <= d6) {
+ result.x = v2X;
+ result.y = v2Y;
+ return POINT_ON_TRIANGLE_VERTEX_2;
+ }
+ float vb = d5 * d2 - d1 * d6;
+ if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
+ float w = d2 / (d2 - d6);
+ result.x = v0X + w * acX;
+ result.y = v0Y + w * acY;
+ return POINT_ON_TRIANGLE_EDGE_20;
+ }
+ float va = d3 * d6 - d5 * d4;
+ if (va <= 0.0f && d4 - d3 >= 0.0f && d5 - d6 >= 0.0f) {
+ float w = (d4 - d3) / (d4 - d3 + d5 - d6);
+ result.x = v1X + w * (v2X - v1X);
+ result.y = v1Y + w * (v2Y - v1Y);
+ return POINT_ON_TRIANGLE_EDGE_12;
+ }
+ float denom = 1.0f / (va + vb + vc);
+ float v = vb * denom;
+ float w = vc * denom;
+ result.x = v0X + abX * v + acX * w;
+ result.y = v0Y + abY * v + acY * w;
+ return POINT_ON_TRIANGLE_FACE;
+ }
+
+ /**
+ * Determine the closest point on the triangle with the vertices v0
, v1
, v2
+ * between that triangle and the given point p
and store that point into the given result
.
+ *
+ * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2})
+ * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20})
+ * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle.
+ *
+ * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point"
+ *
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @param p
+ * the point
+ * @param result
+ * will hold the closest point
+ * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2},
+ * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or
+ * {@link #POINT_ON_TRIANGLE_FACE}
+ */
+ public static int findClosestPointOnTriangle(Vector2fc v0, Vector2fc v1, Vector2fc v2, Vector2fc p, Vector2f result) {
+ return findClosestPointOnTriangle(v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y(), p.x(), p.y(), result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the given circle with center (centerX, centerY)
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the circle
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean intersectRayCircle(float originX, float originY, float dirX, float dirY,
+ float centerX, float centerY, float radiusSquared, Vector2f result) {
+ float Lx = centerX - originX;
+ float Ly = centerY - originY;
+ float tca = Lx * dirX + Ly * dirY;
+ float d2 = Lx * Lx + Ly * Ly - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ float thc = (float) Math.sqrt(radiusSquared - d2);
+ float t0 = tca - thc;
+ float t1 = tca + thc;
+ if (t0 < t1 && t1 >= 0.0f) {
+ result.x = t0;
+ result.y = t1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the circle with the given center
and square radius radiusSquared
,
+ * and store the values of the parameter t in the ray equation p(t) = origin + t * dir for both points (near
+ * and far) of intersections into the given result
vector.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @param result
+ * a vector that will contain the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir for both points (near, far) of intersections with the circle
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean intersectRayCircle(Vector2fc origin, Vector2fc dir, Vector2fc center, float radiusSquared, Vector2f result) {
+ return intersectRayCircle(origin.x(), origin.y(), dir.x(), dir.y(), center.x(), center.y(), radiusSquared, result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the given circle with center (centerX, centerY)
and square radius radiusSquared
.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean testRayCircle(float originX, float originY, float dirX, float dirY,
+ float centerX, float centerY, float radiusSquared) {
+ float Lx = centerX - originX;
+ float Ly = centerY - originY;
+ float tca = Lx * dirX + Ly * dirY;
+ float d2 = Lx * Lx + Ly * Ly - tca * tca;
+ if (d2 > radiusSquared)
+ return false;
+ float thc = (float) Math.sqrt(radiusSquared - d2);
+ float t0 = tca - thc;
+ float t1 = tca + thc;
+ return t0 < t1 && t1 >= 0.0f;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the circle with the given center
and square radius.
+ *
+ * This method returns true
for a ray whose origin lies inside the circle.
+ *
+ * Reference: http://www.scratchapixel.com/
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the circle radius squared
+ * @return true
if the ray intersects the circle; false
otherwise
+ */
+ public static boolean testRayCircle(Vector2fc origin, Vector2fc dir, Vector2fc center, float radiusSquared) {
+ return testRayCircle(origin.x(), origin.y(), dir.x(), dir.y(), center.x(), center.y(), radiusSquared);
+ }
+
+ /**
+ * Determine whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the axis-aligned rectangle given as its minimum corner (minX, minY)
and maximum corner (maxX, maxY)
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * as well as the side of the axis-aligned rectangle the ray intersects.
+ *
+ * This method also detects an intersection for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the near and far point of intersection
+ * @return the side on which the near intersection occurred as one of
+ * {@link #AAR_SIDE_MINX}, {@link #AAR_SIDE_MINY}, {@link #AAR_SIDE_MAXX} or {@link #AAR_SIDE_MAXY};
+ * or -1
if the ray does not intersect the axis-aligned rectangle;
+ */
+ public static int intersectRayAar(float originX, float originY, float dirX, float dirY,
+ float minX, float minY, float maxX, float maxY, Vector2f result) {
+ float invDirX = 1.0f / dirX, invDirY = 1.0f / dirY;
+ float tNear, tFar, tymin, tymax;
+ if (invDirX >= 0.0f) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0f) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return OUTSIDE;
+ tNear = tymin > tNear || Float.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Float.isNaN(tFar) ? tymax : tFar;
+ int side = -1; // no intersection side
+ if (tNear <= tFar && tFar >= 0.0f) {
+ float px = originX + tNear * dirX;
+ float py = originY + tNear * dirY;
+ result.x = tNear;
+ result.y = tFar;
+ float daX = Math.abs(px - minX);
+ float daY = Math.abs(py - minY);
+ float dbX = Math.abs(px - maxX);
+ float dbY = Math.abs(py - maxY);
+ side = 0; // min x coordinate
+ float min = daX;
+ if (daY < min) {
+ min = daY;
+ side = 1; // min y coordinate
+ }
+ if (dbX < min) {
+ min = dbX;
+ side = 2; // max xcoordinate
+ }
+ if (dbY < min)
+ side = 3; // max y coordinate
+ }
+ return side;
+ }
+
+ /**
+ * Determine whether the given ray with the given origin
and direction dir
+ * intersects the axis-aligned rectangle given as its minimum corner min
and maximum corner max
,
+ * and return the values of the parameter t in the ray equation p(t) = origin + t * dir of the near and far point of intersection
+ * as well as the side of the axis-aligned rectangle the ray intersects.
+ *
+ * This method also detects an intersection for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectRayAar(float, float, float, float, float, float, float, float, Vector2f)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = origin + t * dir of the near and far point of intersection
+ * @return the side on which the near intersection occurred as one of
+ * {@link #AAR_SIDE_MINX}, {@link #AAR_SIDE_MINY}, {@link #AAR_SIDE_MAXX} or {@link #AAR_SIDE_MAXY};
+ * or -1
if the ray does not intersect the axis-aligned rectangle;
+ */
+ public static int intersectRayAar(Vector2fc origin, Vector2fc dir, Vector2fc min, Vector2fc max, Vector2f result) {
+ return intersectRayAar(origin.x(), origin.y(), dir.x(), dir.y(), min.x(), min.y(), max.x(), max.y(), result);
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points (p0X, p0Y)
and (p1X, p1Y)
+ * intersects the axis-aligned rectangle given as its minimum corner (minX, minY)
and maximum corner (maxX, maxY)
,
+ * and store the values of the parameter t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * into result
.
+ *
+ * This method also detects an intersection of a line segment whose either end point lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #intersectLineSegmentAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc, Vector2f)
+ *
+ * @param p0X
+ * the x coordinate of the line segment's first end point
+ * @param p0Y
+ * the y coordinate of the line segment's first end point
+ * @param p1X
+ * the x coordinate of the line segment's second end point
+ * @param p1Y
+ * the y coordinate of the line segment's second end point
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned rectangle; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned rectangle; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned rectangle; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two edges of the axis-aligned rectangle or lies on one edge of the rectangle
+ */
+ public static int intersectLineSegmentAar(float p0X, float p0Y, float p1X, float p1Y,
+ float minX, float minY, float maxX, float maxY, Vector2f result) {
+ float dirX = p1X - p0X, dirY = p1Y - p0Y;
+ float invDirX = 1.0f / dirX, invDirY = 1.0f / dirY;
+ float tNear, tFar, tymin, tymax;
+ if (invDirX >= 0.0f) {
+ tNear = (minX - p0X) * invDirX;
+ tFar = (maxX - p0X) * invDirX;
+ } else {
+ tNear = (maxX - p0X) * invDirX;
+ tFar = (minX - p0X) * invDirX;
+ }
+ if (invDirY >= 0.0f) {
+ tymin = (minY - p0Y) * invDirY;
+ tymax = (maxY - p0Y) * invDirY;
+ } else {
+ tymin = (maxY - p0Y) * invDirY;
+ tymax = (minY - p0Y) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return OUTSIDE;
+ tNear = tymin > tNear || Float.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Float.isNaN(tFar) ? tymax : tFar;
+ int type = OUTSIDE;
+ if (tNear <= tFar && tNear <= 1.0f && tFar >= 0.0f) {
+ if (tNear >= 0.0f && tFar > 1.0f) {
+ tFar = tNear;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar <= 1.0f) {
+ tNear = tFar;
+ type = ONE_INTERSECTION;
+ } else if (tNear < 0.0f && tFar > 1.0f) {
+ type = INSIDE;
+ } else {
+ type = TWO_INTERSECTION;
+ }
+ result.x = tNear;
+ result.y = tFar;
+ }
+ return type;
+ }
+
+ /**
+ * Determine whether the undirected line segment with the end points p0
and p1
+ * intersects the axis-aligned rectangle given as its minimum corner min
and maximum corner max
,
+ * and store the values of the parameter t in the ray equation p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * into result
.
+ *
+ * This method also detects an intersection of a line segment whose either end point lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * #see {@link #intersectLineSegmentAar(float, float, float, float, float, float, float, float, Vector2f)}
+ *
+ * @param p0
+ * the line segment's first end point
+ * @param p1
+ * the line segment's second end point
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @param result
+ * a vector which will hold the values of the parameter t in the ray equation
+ * p(t) = p0 + t * (p1 - p0) of the near and far point of intersection
+ * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned rectangle; or
+ * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned rectangle; or
+ * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned rectangle; or
+ * {@link #TWO_INTERSECTION} if the line segment intersects two edges of the axis-aligned rectangle
+ */
+ public static int intersectLineSegmentAar(Vector2fc p0, Vector2fc p1, Vector2fc min, Vector2fc max, Vector2f result) {
+ return intersectLineSegmentAar(p0.x(), p0.y(), p1.x(), p1.y(), min.x(), min.y(), max.x(), max.y(), result);
+ }
+
+ /**
+ * Test whether the given ray with the origin (originX, originY)
and direction (dirX, dirY)
+ * intersects the given axis-aligned rectangle given as its minimum corner (minX, minY)
and maximum corner (maxX, maxY)
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAar(Vector2fc, Vector2fc, Vector2fc, Vector2fc)
+ *
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @return true
if the given ray intersects the axis-aligned rectangle; false
otherwise
+ */
+ public static boolean testRayAar(float originX, float originY, float dirX, float dirY, float minX, float minY, float maxX, float maxY) {
+ float invDirX = 1.0f / dirX, invDirY = 1.0f / dirY;
+ float tNear, tFar, tymin, tymax;
+ if (invDirX >= 0.0f) {
+ tNear = (minX - originX) * invDirX;
+ tFar = (maxX - originX) * invDirX;
+ } else {
+ tNear = (maxX - originX) * invDirX;
+ tFar = (minX - originX) * invDirX;
+ }
+ if (invDirY >= 0.0f) {
+ tymin = (minY - originY) * invDirY;
+ tymax = (maxY - originY) * invDirY;
+ } else {
+ tymin = (maxY - originY) * invDirY;
+ tymax = (minY - originY) * invDirY;
+ }
+ if (tNear > tymax || tymin > tFar)
+ return false;
+ tNear = tymin > tNear || Float.isNaN(tNear) ? tymin : tNear;
+ tFar = tymax < tFar || Float.isNaN(tFar) ? tymax : tFar;
+ return tNear < tFar && tFar >= 0.0f;
+ }
+
+ /**
+ * Test whether the ray with the given origin
and direction dir
+ * intersects the given axis-aligned rectangle specified as its minimum corner min
and maximum corner max
.
+ *
+ * This method returns true
for a ray whose origin lies inside the axis-aligned rectangle.
+ *
+ * Reference: An Efficient and Robust Ray–Box Intersection
+ *
+ * @see #testRayAar(float, float, float, float, float, float, float, float)
+ *
+ * @param origin
+ * the ray's origin
+ * @param dir
+ * the ray's direction
+ * @param min
+ * the minimum corner of the axis-aligned rectangle
+ * @param max
+ * the maximum corner of the axis-aligned rectangle
+ * @return true
if the given ray intersects the axis-aligned rectangle; false
otherwise
+ */
+ public static boolean testRayAar(Vector2fc origin, Vector2fc dir, Vector2fc min, Vector2fc max) {
+ return testRayAar(origin.x(), origin.y(), dir.x(), dir.y(), min.x(), min.y(), max.x(), max.y());
+ }
+
+ /**
+ * Test whether the given point (pX, pY)
lies inside the triangle with the vertices (v0X, v0Y)
, (v1X, v1Y)
, (v2X, v2Y)
.
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @return true
iff the point lies inside the triangle; false
otherwise
+ */
+ public static boolean testPointTriangle(float pX, float pY, float v0X, float v0Y, float v1X, float v1Y, float v2X, float v2Y) {
+ boolean b1 = (pX - v1X) * (v0Y - v1Y) - (v0X - v1X) * (pY - v1Y) < 0.0f;
+ boolean b2 = (pX - v2X) * (v1Y - v2Y) - (v1X - v2X) * (pY - v2Y) < 0.0f;
+ if (b1 != b2)
+ return false;
+ boolean b3 = (pX - v0X) * (v2Y - v0Y) - (v2X - v0X) * (pY - v0Y) < 0.0f;
+ return b2 == b3;
+ }
+
+ /**
+ * Test whether the given point
lies inside the triangle with the vertices v0
, v1
, v2
.
+ *
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @param point
+ * the point
+ * @return true
iff the point lies inside the triangle; false
otherwise
+ */
+ public static boolean testPointTriangle(Vector2fc point, Vector2fc v0, Vector2fc v1, Vector2fc v2) {
+ return testPointTriangle(point.x(), point.y(), v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y());
+ }
+
+ /**
+ * Test whether the given point (pX, pY)
lies inside the axis-aligned rectangle with the minimum corner (minX, minY)
+ * and maximum corner (maxX, maxY)
.
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned rectangle
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned rectangle
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned rectangle
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned rectangle
+ * @return true
iff the point lies inside the axis-aligned rectangle; false
otherwise
+ */
+ public static boolean testPointAar(float pX, float pY, float minX, float minY, float maxX, float maxY) {
+ return pX >= minX && pY >= minY && pX <= maxX && pY <= maxY;
+ }
+
+ /**
+ * Test whether the point (pX, pY)
lies inside the circle with center (centerX, centerY)
and square radius radiusSquared
.
+ *
+ * @param pX
+ * the x coordinate of the point
+ * @param pY
+ * the y coordinate of the point
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the square radius of the circle
+ * @return true
iff the point lies inside the circle; false
otherwise
+ */
+ public static boolean testPointCircle(float pX, float pY, float centerX, float centerY, float radiusSquared) {
+ float dx = pX - centerX;
+ float dy = pY - centerY;
+ float dx2 = dx * dx;
+ float dy2 = dy * dy;
+ return dx2 + dy2 <= radiusSquared;
+ }
+
+ /**
+ * Test whether the circle with center (centerX, centerY)
and square radius radiusSquared
intersects the triangle with counter-clockwise vertices
+ * (v0X, v0Y)
, (v1X, v1Y)
, (v2X, v2Y)
.
+ *
+ * The vertices of the triangle must be specified in counter-clockwise order.
+ *
+ * Reference: http://www.phatcode.net/
+ *
+ * @param centerX
+ * the x coordinate of the circle's center
+ * @param centerY
+ * the y coordinate of the circle's center
+ * @param radiusSquared
+ * the square radius of the circle
+ * @param v0X
+ * the x coordinate of the first vertex of the triangle
+ * @param v0Y
+ * the y coordinate of the first vertex of the triangle
+ * @param v1X
+ * the x coordinate of the second vertex of the triangle
+ * @param v1Y
+ * the y coordinate of the second vertex of the triangle
+ * @param v2X
+ * the x coordinate of the third vertex of the triangle
+ * @param v2Y
+ * the y coordinate of the third vertex of the triangle
+ * @return true
iff the circle intersects the triangle; false
otherwise
+ */
+ public static boolean testCircleTriangle(float centerX, float centerY, float radiusSquared, float v0X, float v0Y, float v1X, float v1Y, float v2X, float v2Y) {
+ float c1x = centerX - v0X, c1y = centerY - v0Y;
+ float c1sqr = c1x * c1x + c1y * c1y - radiusSquared;
+ if (c1sqr <= 0.0f)
+ return true;
+ float c2x = centerX - v1X, c2y = centerY - v1Y;
+ float c2sqr = c2x * c2x + c2y * c2y - radiusSquared;
+ if (c2sqr <= 0.0f)
+ return true;
+ float c3x = centerX - v2X, c3y = centerY - v2Y;
+ float c3sqr = c3x * c3x + c3y * c3y - radiusSquared;
+ if (c3sqr <= 0.0f)
+ return true;
+ float e1x = v1X - v0X, e1y = v1Y - v0Y;
+ float e2x = v2X - v1X, e2y = v2Y - v1Y;
+ float e3x = v0X - v2X, e3y = v0Y - v2Y;
+ if (e1x * c1y - e1y * c1x >= 0.0f && e2x * c2y - e2y * c2x >= 0.0f && e3x * c3y - e3y * c3x >= 0.0f)
+ return true;
+ float k = c1x * e1x + c1y * e1y;
+ if (k >= 0.0f) {
+ float len = e1x * e1x + e1y * e1y;
+ if (k <= len) {
+ if (c1sqr * len <= k * k)
+ return true;
+ }
+ }
+ k = c2x * e2x + c2y * e2y;
+ if (k > 0.0f) {
+ float len = e2x * e2x + e2y * e2y;
+ if (k <= len) {
+ if (c2sqr * len <= k * k)
+ return true;
+ }
+ }
+ k = c3x * e3x + c3y * e3y;
+ if (k >= 0.0f) {
+ float len = e3x * e3x + e3y * e3y;
+ if (k < len) {
+ if (c3sqr * len <= k * k)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Test whether the circle with given center
and square radius radiusSquared
intersects the triangle with counter-clockwise vertices
+ * v0
, v1
, v2
.
+ *
+ * The vertices of the triangle must be specified in counter-clockwise order.
+ *
+ * Reference: http://www.phatcode.net/
+ *
+ * @param center
+ * the circle's center
+ * @param radiusSquared
+ * the square radius of the circle
+ * @param v0
+ * the first vertex of the triangle
+ * @param v1
+ * the second vertex of the triangle
+ * @param v2
+ * the third vertex of the triangle
+ * @return true
iff the circle intersects the triangle; false
otherwise
+ */
+ public static boolean testCircleTriangle(Vector2fc center, float radiusSquared, Vector2fc v0, Vector2fc v1, Vector2fc v2) {
+ return testCircleTriangle(center.x(), center.y(), radiusSquared, v0.x(), v0.y(), v1.x(), v1.y(), v2.x(), v2.y());
+ }
+
+ /**
+ * Determine whether the polygon specified by the given sequence of (x, y)
coordinate pairs intersects with the ray
+ * with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
, and store the point of intersection
+ * into the given vector p
.
+ *
+ * If the polygon intersects the ray, this method returns the index of the polygon edge intersecting the ray, that is, the index of the
+ * first vertex of the directed line segment. The second vertex is always that index + 1, modulus the number of polygon vertices.
+ *
+ * @param verticesXY
+ * the sequence of (x, y)
coordinate pairs of all vertices of the polygon
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param p
+ * will hold the point of intersection
+ * @return the index of the first vertex of the polygon edge that intersects the ray; or -1
if the ray does not intersect the polygon
+ */
+ public static int intersectPolygonRay(float[] verticesXY, float originX, float originY, float dirX, float dirY, Vector2f p) {
+ float nearestT = Float.POSITIVE_INFINITY;
+ int count = verticesXY.length >> 1;
+ int edgeIndex = -1;
+ float aX = verticesXY[(count-1)<<1], aY = verticesXY[((count-1)<<1) + 1];
+ for (int i = 0; i < count; i++) {
+ float bX = verticesXY[i << 1], bY = verticesXY[(i << 1) + 1];
+ float doaX = originX - aX, doaY = originY - aY;
+ float dbaX = bX - aX, dbaY = bY - aY;
+ float invDbaDir = 1.0f / (dbaY * dirX - dbaX * dirY);
+ float t = (dbaX * doaY - dbaY * doaX) * invDbaDir;
+ if (t >= 0.0f && t < nearestT) {
+ float t2 = (doaY * dirX - doaX * dirY) * invDbaDir;
+ if (t2 >= 0.0f && t2 <= 1.0f) {
+ edgeIndex = (i - 1 + count) % count;
+ nearestT = t;
+ p.x = originX + t * dirX;
+ p.y = originY + t * dirY;
+ }
+ }
+ aX = bX;
+ aY = bY;
+ }
+ return edgeIndex;
+ }
+
+ /**
+ * Determine whether the polygon specified by the given sequence of vertices
intersects with the ray
+ * with given origin (originX, originY, originZ)
and direction (dirX, dirY, dirZ)
, and store the point of intersection
+ * into the given vector p
.
+ *
+ * If the polygon intersects the ray, this method returns the index of the polygon edge intersecting the ray, that is, the index of the
+ * first vertex of the directed line segment. The second vertex is always that index + 1, modulus the number of polygon vertices.
+ *
+ * @param vertices
+ * the sequence of (x, y)
coordinate pairs of all vertices of the polygon
+ * @param originX
+ * the x coordinate of the ray's origin
+ * @param originY
+ * the y coordinate of the ray's origin
+ * @param dirX
+ * the x coordinate of the ray's direction
+ * @param dirY
+ * the y coordinate of the ray's direction
+ * @param p
+ * will hold the point of intersection
+ * @return the index of the first vertex of the polygon edge that intersects the ray; or -1
if the ray does not intersect the polygon
+ */
+ public static int intersectPolygonRay(Vector2fc[] vertices, float originX, float originY, float dirX, float dirY, Vector2f p) {
+ float nearestT = Float.POSITIVE_INFINITY;
+ int count = vertices.length;
+ int edgeIndex = -1;
+ float aX = vertices[count-1].x(), aY = vertices[count-1].y();
+ for (int i = 0; i < count; i++) {
+ Vector2fc b = vertices[i];
+ float bX = b.x(), bY = b.y();
+ float doaX = originX - aX, doaY = originY - aY;
+ float dbaX = bX - aX, dbaY = bY - aY;
+ float invDbaDir = 1.0f / (dbaY * dirX - dbaX * dirY);
+ float t = (dbaX * doaY - dbaY * doaX) * invDbaDir;
+ if (t >= 0.0f && t < nearestT) {
+ float t2 = (doaY * dirX - doaX * dirY) * invDbaDir;
+ if (t2 >= 0.0f && t2 <= 1.0f) {
+ edgeIndex = (i - 1 + count) % count;
+ nearestT = t;
+ p.x = originX + t * dirX;
+ p.y = originY + t * dirY;
+ }
+ }
+ aX = bX;
+ aY = bY;
+ }
+ return edgeIndex;
+ }
+
+ /**
+ * Determine whether the two lines, specified via two points lying on each line, intersect each other, and store the point of intersection
+ * into the given vector p
.
+ *
+ * @param ps1x
+ * the x coordinate of the first point on the first line
+ * @param ps1y
+ * the y coordinate of the first point on the first line
+ * @param pe1x
+ * the x coordinate of the second point on the first line
+ * @param pe1y
+ * the y coordinate of the second point on the first line
+ * @param ps2x
+ * the x coordinate of the first point on the second line
+ * @param ps2y
+ * the y coordinate of the first point on the second line
+ * @param pe2x
+ * the x coordinate of the second point on the second line
+ * @param pe2y
+ * the y coordinate of the second point on the second line
+ * @param p
+ * will hold the point of intersection
+ * @return true
iff the two lines intersect; false
otherwise
+ */
+ public static boolean intersectLineLine(float ps1x, float ps1y, float pe1x, float pe1y, float ps2x, float ps2y, float pe2x, float pe2y, Vector2f p) {
+ float d1x = ps1x - pe1x;
+ float d1y = pe1y - ps1y;
+ float d1ps1 = d1y * ps1x + d1x * ps1y;
+ float d2x = ps2x - pe2x;
+ float d2y = pe2y - ps2y;
+ float d2ps2 = d2y * ps2x + d2x * ps2y;
+ float det = d1y * d2x - d2y * d1x;
+ if (det == 0.0f)
+ return false;
+ p.x = (d2x * d1ps1 - d1x * d2ps2) / det;
+ p.y = (d1y * d2ps2 - d2y * d1ps1) / det;
+ return true;
+ }
+
+ private static boolean separatingAxis(Vector2f[] v1s, Vector2f[] v2s, float aX, float aY) {
+ float minA = Float.POSITIVE_INFINITY, maxA = Float.NEGATIVE_INFINITY;
+ float minB = Float.POSITIVE_INFINITY, maxB = Float.NEGATIVE_INFINITY;
+ int maxLen = Math.max(v1s.length, v2s.length);
+ /* Project both polygons on axis */
+ for (int k = 0; k < maxLen; k++) {
+ if (k < v1s.length) {
+ Vector2f v1 = v1s[k];
+ float d = v1.x * aX + v1.y * aY;
+ if (d < minA) minA = d;
+ if (d > maxA) maxA = d;
+ }
+ if (k < v2s.length) {
+ Vector2f v2 = v2s[k];
+ float d = v2.x * aX + v2.y * aY;
+ if (d < minB) minB = d;
+ if (d > maxB) maxB = d;
+ }
+ /* Early-out if overlap found */
+ if (minA <= maxB && minB <= maxA) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test if the two convex polygons, given via their vertices, intersect.
+ *
+ * @param v1s
+ * the vertices of the first convex polygon
+ * @param v2s
+ * the vertices of the second convex polygon
+ * @return true
if the convex polygons intersect; false
otherwise
+ */
+ public static boolean testPolygonPolygon(Vector2f[] v1s, Vector2f[] v2s) {
+ /* Try to find a separating axis using the first polygon's edges */
+ for (int i = 0, j = v1s.length - 1; i < v1s.length; j = i, i++) {
+ Vector2f s = v1s[i], t = v1s[j];
+ if (separatingAxis(v1s, v2s, s.y - t.y, t.x - s.x))
+ return false;
+ }
+ /* Try to find a separating axis using the second polygon's edges */
+ for (int i = 0, j = v2s.length - 1; i < v2s.length; j = i, i++) {
+ Vector2f s = v2s[i], t = v2s[j];
+ if (separatingAxis(v1s, v2s, s.y - t.y, t.x - s.x))
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Math.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Math.java
new file mode 100644
index 000000000..147dd0af5
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Math.java
@@ -0,0 +1,566 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Contains fast approximations of some {@link java.lang.Math} operations.
+ *
+ * By default, {@link java.lang.Math} methods will be used by all other JOML classes. In order to use the approximations in this class, start the JVM with the parameter -Djoml.fastmath
.
+ *
+ * There are two algorithms for approximating sin/cos:
+ *
+ * - arithmetic polynomial approximation contributed by roquendm
+ *
- theagentd's linear interpolation variant of Riven's algorithm from
+ * http://www.java-gaming.org/
+ *
+ * By default, the first algorithm is being used. In order to use the second one, start the JVM with -Djoml.sinLookup
. The lookup table bit length of the second algorithm can also be adjusted
+ * for improved accuracy via -Djoml.sinLookup.bits=<n>
, where <n> is the number of bits of the lookup table.
+ *
+ * @author Kai Burjack
+ */
+public class Math {
+
+ /*
+ * The following implementation of an approximation of sine and cosine was
+ * thankfully donated by Riven from http://java-gaming.org/.
+ *
+ * The code for linear interpolation was gratefully donated by theagentd
+ * from the same site.
+ */
+ public static final double PI = java.lang.Math.PI;
+ static final double PI2 = PI * 2.0;
+ static final float PI_f = (float) java.lang.Math.PI;
+ static final float PI2_f = PI_f * 2.0f;
+ static final double PIHalf = PI * 0.5;
+ static final float PIHalf_f = (float) (PI * 0.5);
+ static final double PI_4 = PI * 0.25;
+ static final double PI_INV = 1.0 / PI;
+ private static final int lookupBits = Options.SIN_LOOKUP_BITS;
+ private static final int lookupTableSize = 1 << lookupBits;
+ private static final int lookupTableSizeMinus1 = lookupTableSize - 1;
+ private static final int lookupTableSizeWithMargin = lookupTableSize + 1;
+ private static final float pi2OverLookupSize = PI2_f / lookupTableSize;
+ private static final float lookupSizeOverPi2 = lookupTableSize / PI2_f;
+ private static final float sinTable[];
+ static {
+ if (Options.FASTMATH && Options.SIN_LOOKUP) {
+ sinTable = new float[lookupTableSizeWithMargin];
+ for (int i = 0; i < lookupTableSizeWithMargin; i++) {
+ double d = i * pi2OverLookupSize;
+ sinTable[i] = (float) java.lang.Math.sin(d);
+ }
+ } else {
+ sinTable = null;
+ }
+ }
+
+ private static final double c1 = Double.longBitsToDouble(-4628199217061079772L);
+ private static final double c2 = Double.longBitsToDouble(4575957461383582011L);
+ private static final double c3 = Double.longBitsToDouble(-4671919876300759001L);
+ private static final double c4 = Double.longBitsToDouble(4523617214285661942L);
+ private static final double c5 = Double.longBitsToDouble(-4730215272828025532L);
+ private static final double c6 = Double.longBitsToDouble(4460272573143870633L);
+ private static final double c7 = Double.longBitsToDouble(-4797767418267846529L);
+
+ /**
+ * @author theagentd
+ */
+ static double sin_theagentd_arith(double x){
+ double xi = floor((x + PI_4) * PI_INV);
+ double x_ = x - xi * PI;
+ double sign = ((int)xi & 1) * -2 + 1;
+ double x2 = x_ * x_;
+ double sin = x_;
+ double tx = x_ * x2;
+ sin += tx * c1; tx *= x2;
+ sin += tx * c2; tx *= x2;
+ sin += tx * c3; tx *= x2;
+ sin += tx * c4; tx *= x2;
+ sin += tx * c5; tx *= x2;
+ sin += tx * c6; tx *= x2;
+ sin += tx * c7;
+ return sign * sin;
+ }
+
+ /**
+ * Reference: http://www.java-gaming.org/
+ */
+ static double sin_roquen_arith(double x) {
+ double xi = Math.floor((x + PI_4) * PI_INV);
+ double x_ = x - xi * PI;
+ double sign = ((int)xi & 1) * -2 + 1;
+ double x2 = x_ * x_;
+
+ // code from sin_theagentd_arith:
+ // double sin = x_;
+ // double tx = x_ * x2;
+ // sin += tx * c1; tx *= x2;
+ // sin += tx * c2; tx *= x2;
+ // sin += tx * c3; tx *= x2;
+ // sin += tx * c4; tx *= x2;
+ // sin += tx * c5; tx *= x2;
+ // sin += tx * c6; tx *= x2;
+ // sin += tx * c7;
+ // return sign * sin;
+
+ double sin;
+ x_ = sign*x_;
+ sin = c7;
+ sin = sin*x2 + c6;
+ sin = sin*x2 + c5;
+ sin = sin*x2 + c4;
+ sin = sin*x2 + c3;
+ sin = sin*x2 + c2;
+ sin = sin*x2 + c1;
+ return x_ + x_*x2*sin;
+ }
+
+ private static final double s5 = Double.longBitsToDouble(4523227044276562163L);
+ private static final double s4 = Double.longBitsToDouble(-4671934770969572232L);
+ private static final double s3 = Double.longBitsToDouble(4575957211482072852L);
+ private static final double s2 = Double.longBitsToDouble(-4628199223918090387L);
+ private static final double s1 = Double.longBitsToDouble(4607182418589157889L);
+
+ /**
+ * Reference: http://www.java-gaming.org/
+ */
+ static double sin_roquen_9(double v) {
+ double i = java.lang.Math.rint(v*PI_INV);
+ double x = v - i * Math.PI;
+ double qs = 1-2*((int)i & 1);
+ double x2 = x*x;
+ double r;
+ x = qs*x;
+ r = s5;
+ r = r*x2 + s4;
+ r = r*x2 + s3;
+ r = r*x2 + s2;
+ r = r*x2 + s1;
+ return x*r;
+ }
+
+ private static final double k1 = Double.longBitsToDouble(-4628199217061079959L);
+ private static final double k2 = Double.longBitsToDouble(4575957461383549981L);
+ private static final double k3 = Double.longBitsToDouble(-4671919876307284301L);
+ private static final double k4 = Double.longBitsToDouble(4523617213632129738L);
+ private static final double k5 = Double.longBitsToDouble(-4730215344060517252L);
+ private static final double k6 = Double.longBitsToDouble(4460268259291226124L);
+ private static final double k7 = Double.longBitsToDouble(-4798040743777455072L);
+
+ /**
+ * Reference: http://www.java-gaming.org/
+ */
+ static double sin_roquen_newk(double v) {
+ double i = java.lang.Math.rint(v*PI_INV);
+ double x = v - i * Math.PI;
+ double qs = 1-2*((int)i & 1);
+ double x2 = x*x;
+ double r;
+ x = qs*x;
+ r = k7;
+ r = r*x2 + k6;
+ r = r*x2 + k5;
+ r = r*x2 + k4;
+ r = r*x2 + k3;
+ r = r*x2 + k2;
+ r = r*x2 + k1;
+ return x + x*x2*r;
+ }
+
+ /**
+ * Reference: http://www.java-gaming.org/
+ */
+ static float sin_theagentd_lookup(float rad) {
+ float index = rad * lookupSizeOverPi2;
+ int ii = (int)java.lang.Math.floor(index);
+ float alpha = index - ii;
+ int i = ii & lookupTableSizeMinus1;
+ float sin1 = sinTable[i];
+ float sin2 = sinTable[i + 1];
+ return sin1 + (sin2 - sin1) * alpha;
+ }
+
+ public static float sin(float rad) {
+ return (float) java.lang.Math.sin(rad);
+ }
+ public static double sin(double rad) {
+ if (Options.FASTMATH) {
+ if (Options.SIN_LOOKUP)
+ return sin_theagentd_lookup((float) rad);
+ return sin_roquen_newk(rad);
+ }
+ return java.lang.Math.sin(rad);
+ }
+
+ public static float cos(float rad) {
+ if (Options.FASTMATH)
+ return sin(rad + PIHalf_f);
+ return (float) java.lang.Math.cos(rad);
+ }
+ public static double cos(double rad) {
+ if (Options.FASTMATH)
+ return sin(rad + PIHalf);
+ return java.lang.Math.cos(rad);
+ }
+
+ public static float cosFromSin(float sin, float angle) {
+ if (Options.FASTMATH)
+ return sin(angle + PIHalf_f);
+ return cosFromSinInternal(sin, angle);
+ }
+ private static float cosFromSinInternal(float sin, float angle) {
+ // sin(x)^2 + cos(x)^2 = 1
+ float cos = sqrt(1.0f - sin * sin);
+ float a = angle + PIHalf_f;
+ float b = a - (int)(a / PI2_f) * PI2_f;
+ if (b < 0.0)
+ b = PI2_f + b;
+ if (b >= PI_f)
+ return -cos;
+ return cos;
+ }
+ public static double cosFromSin(double sin, double angle) {
+ if (Options.FASTMATH)
+ return sin(angle + PIHalf);
+ // sin(x)^2 + cos(x)^2 = 1
+ double cos = sqrt(1.0 - sin * sin);
+ double a = angle + PIHalf;
+ double b = a - (int)(a / PI2) * PI2;
+ if (b < 0.0)
+ b = PI2 + b;
+ if (b >= PI)
+ return -cos;
+ return cos;
+ }
+
+ /* Other math functions not yet approximated */
+
+ public static float sqrt(float r) {
+ return (float) java.lang.Math.sqrt(r);
+ }
+ public static double sqrt(double r) {
+ return java.lang.Math.sqrt(r);
+ }
+
+ public static float invsqrt(float r) {
+ return 1.0f / (float) java.lang.Math.sqrt(r);
+ }
+ public static double invsqrt(double r) {
+ return 1.0 / java.lang.Math.sqrt(r);
+ }
+
+ public static float tan(float r) {
+ return (float) java.lang.Math.tan(r);
+ }
+ public static double tan(double r) {
+ return java.lang.Math.tan(r);
+ }
+
+ public static float acos(float r) {
+ return (float) java.lang.Math.acos(r);
+ }
+ public static double acos(double r) {
+ return java.lang.Math.acos(r);
+ }
+
+ public static float safeAcos(float v) {
+ if (v < -1.0f)
+ return Math.PI_f;
+ else if (v > +1.0f)
+ return 0.0f;
+ else
+ return acos(v);
+ }
+ public static double safeAcos(double v) {
+ if (v < -1.0)
+ return Math.PI;
+ else if (v > +1.0)
+ return 0.0;
+ else
+ return acos(v);
+ }
+
+ /**
+ * https://math.stackexchange.com/questions/1098487/atan2-faster-approximation/1105038#answer-1105038
+ */
+ private static double fastAtan2(double y, double x) {
+ double ax = x >= 0.0 ? x : -x, ay = y >= 0.0 ? y : -y;
+ double a = min(ax, ay) / max(ax, ay);
+ double s = a * a;
+ double r = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a;
+ if (ay > ax)
+ r = 1.57079637 - r;
+ if (x < 0.0)
+ r = 3.14159274 - r;
+ return y >= 0 ? r : -r;
+ }
+
+ public static float atan2(float y, float x) {
+ return (float) java.lang.Math.atan2(y, x);
+ }
+ public static double atan2(double y, double x) {
+ if (Options.FASTMATH)
+ return fastAtan2(y, x);
+ return java.lang.Math.atan2(y, x);
+ }
+
+ public static float asin(float r) {
+ return (float) java.lang.Math.asin(r);
+ }
+ public static double asin(double r) {
+ return java.lang.Math.asin(r);
+ }
+ public static float safeAsin(float r) {
+ return r <= -1.0f ? -PIHalf_f : r >= 1.0f ? PIHalf_f : asin(r);
+ }
+ public static double safeAsin(double r) {
+ return r <= -1.0 ? -PIHalf : r >= 1.0 ? PIHalf : asin(r);
+ }
+
+ public static float abs(float r) {
+ return java.lang.Math.abs(r);
+ }
+ public static double abs(double r) {
+ return java.lang.Math.abs(r);
+ }
+
+ static boolean absEqualsOne(float r) {
+ return (Float.floatToRawIntBits(r) & 0x7FFFFFFF) == 0x3F800000;
+ }
+ static boolean absEqualsOne(double r) {
+ return (Double.doubleToRawLongBits(r) & 0x7FFFFFFFFFFFFFFFL) == 0x3FF0000000000000L;
+ }
+
+ public static int abs(int r) {
+ return java.lang.Math.abs(r);
+ }
+
+ public static int max(int x, int y) {
+ return java.lang.Math.max(x, y);
+ }
+
+ public static int min(int x, int y) {
+ return java.lang.Math.min(x, y);
+ }
+
+ public static double min(double a, double b) {
+ return a < b ? a : b;
+ }
+ public static float min(float a, float b) {
+ return a < b ? a : b;
+ }
+
+ public static float max(float a, float b) {
+ return a > b ? a : b;
+ }
+ public static double max(double a, double b) {
+ return a > b ? a : b;
+ }
+
+ public static float clamp(float a, float b, float val){
+ return max(a,min(b,val));
+ }
+ public static double clamp(double a, double b, double val) {
+ return max(a,min(b,val));
+ }
+ public static int clamp(int a, int b, int val) {
+ return max(a, min(b, val));
+ }
+
+ public static float toRadians(float angles) {
+ return (float) java.lang.Math.toRadians(angles);
+ }
+ public static double toRadians(double angles) {
+ return java.lang.Math.toRadians(angles);
+ }
+
+ public static double toDegrees(double angles) {
+ return java.lang.Math.toDegrees(angles);
+ }
+
+ public static double floor(double v) {
+ return java.lang.Math.floor(v);
+ }
+
+ public static float floor(float v) {
+ return (float) java.lang.Math.floor(v);
+ }
+
+ public static double ceil(double v) {
+ return java.lang.Math.ceil(v);
+ }
+
+ public static float ceil(float v) {
+ return (float) java.lang.Math.ceil(v);
+ }
+
+ public static long round(double v) {
+ return java.lang.Math.round(v);
+ }
+
+ public static int round(float v) {
+ return java.lang.Math.round(v);
+ }
+
+ public static double exp(double a) {
+ return java.lang.Math.exp(a);
+ }
+
+ public static boolean isFinite(double d) {
+ return abs(d) <= Double.MAX_VALUE;
+ }
+
+ public static boolean isFinite(float f) {
+ return abs(f) <= Float.MAX_VALUE;
+ }
+
+ public static float fma(float a, float b, float c) {
+ if (Runtime.HAS_Math_fma)
+ return java.lang.Math.fma(a, b, c);
+ return a * b + c;
+ }
+
+ public static double fma(double a, double b, double c) {
+ if (Runtime.HAS_Math_fma)
+ return java.lang.Math.fma(a, b, c);
+ return a * b + c;
+ }
+
+ public static int roundUsing(float v, int mode) {
+ switch (mode) {
+ case RoundingMode.TRUNCATE:
+ return (int) v;
+ case RoundingMode.CEILING:
+ return (int) java.lang.Math.ceil(v);
+ case RoundingMode.FLOOR:
+ return (int) java.lang.Math.floor(v);
+ case RoundingMode.HALF_DOWN:
+ return roundHalfDown(v);
+ case RoundingMode.HALF_UP:
+ return roundHalfUp(v);
+ case RoundingMode.HALF_EVEN:
+ return roundHalfEven(v);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ public static int roundUsing(double v, int mode) {
+ switch (mode) {
+ case RoundingMode.TRUNCATE:
+ return (int) v;
+ case RoundingMode.CEILING:
+ return (int) java.lang.Math.ceil(v);
+ case RoundingMode.FLOOR:
+ return (int) java.lang.Math.floor(v);
+ case RoundingMode.HALF_DOWN:
+ return roundHalfDown(v);
+ case RoundingMode.HALF_UP:
+ return roundHalfUp(v);
+ case RoundingMode.HALF_EVEN:
+ return roundHalfEven(v);
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static float lerp(float a, float b, float t){
+ return Math.fma(b - a, t, a);
+ }
+ public static double lerp(double a, double b, double t) {
+ return Math.fma(b - a, t, a);
+ }
+
+ public static float biLerp(float q00, float q10, float q01, float q11, float tx, float ty) {
+ float lerpX1 = lerp(q00, q10, tx);
+ float lerpX2 = lerp(q01, q11, tx);
+ return lerp(lerpX1, lerpX2, ty);
+ }
+
+ public static double biLerp(double q00, double q10, double q01, double q11, double tx, double ty) {
+ double lerpX1 = lerp(q00, q10, tx);
+ double lerpX2 = lerp(q01, q11, tx);
+ return lerp(lerpX1, lerpX2, ty);
+ }
+
+ public static float triLerp(float q000, float q100, float q010, float q110, float q001, float q101, float q011, float q111, float tx, float ty, float tz) {
+ float x00 = lerp(q000, q100, tx);
+ float x10 = lerp(q010, q110, tx);
+ float x01 = lerp(q001, q101, tx);
+ float x11 = lerp(q011, q111, tx);
+ float y0 = lerp(x00, x10, ty);
+ float y1 = lerp(x01, x11, ty);
+ return lerp(y0, y1, tz);
+ }
+
+ public static double triLerp(double q000, double q100, double q010, double q110, double q001, double q101, double q011, double q111, double tx, double ty, double tz) {
+ double x00 = lerp(q000, q100, tx);
+ double x10 = lerp(q010, q110, tx);
+ double x01 = lerp(q001, q101, tx);
+ double x11 = lerp(q011, q111, tx);
+ double y0 = lerp(x00, x10, ty);
+ double y1 = lerp(x01, x11, ty);
+ return lerp(y0, y1, tz);
+ }
+
+ public static int roundHalfEven(float v) {
+ return (int) java.lang.Math.rint(v);
+ }
+ public static int roundHalfDown(float v) {
+ return (v > 0) ? (int) java.lang.Math.ceil(v - 0.5d) : (int) java.lang.Math.floor(v + 0.5d);
+ }
+ public static int roundHalfUp(float v) {
+ return (v > 0) ? (int) java.lang.Math.floor(v + 0.5d) : (int) java.lang.Math.ceil(v - 0.5d);
+ }
+
+ public static int roundHalfEven(double v) {
+ return (int) java.lang.Math.rint(v);
+ }
+ public static int roundHalfDown(double v) {
+ return (v > 0) ? (int) java.lang.Math.ceil(v - 0.5d) : (int) java.lang.Math.floor(v + 0.5d);
+ }
+ public static int roundHalfUp(double v) {
+ return (v > 0) ? (int) java.lang.Math.floor(v + 0.5d) : (int) java.lang.Math.ceil(v - 0.5d);
+ }
+
+ public static double random() {
+ return java.lang.Math.random();
+ }
+
+ public static double signum(double v) {
+ return java.lang.Math.signum(v);
+ }
+ public static float signum(float v) {
+ return java.lang.Math.signum(v);
+ }
+ public static int signum(int v) {
+ int r;
+ r = Integer.signum(v);
+ return r;
+ }
+ public static int signum(long v) {
+ int r;
+ r = Long.signum(v);
+ return r;
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2d.java
new file mode 100644
index 000000000..e589a5fea
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2d.java
@@ -0,0 +1,1536 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2020-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a 2x2 matrix of doubles, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10
+ * m01 m11
+ *
+ * @author Joseph Burton
+ */
+public class Matrix2d implements Externalizable, Cloneable, Matrix2dc {
+
+ private static final long serialVersionUID = 1L;
+
+ public double m00, m01;
+ public double m10, m11;
+
+ /**
+ * Create a new {@link Matrix2d} and set it to {@link #identity() identity}.
+ */
+ public Matrix2d() {
+ m00 = 1.0;
+ m11 = 1.0;
+ }
+
+ /**
+ * Create a new {@link Matrix2d} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix2dc} to copy the values from
+ */
+ public Matrix2d(Matrix2dc mat) {
+ if (mat instanceof Matrix2d) {
+ MemUtil.INSTANCE.copy((Matrix2d) mat, this);
+ } else {
+ setMatrix2dc(mat);
+ }
+ }
+
+ /**
+ * Create a new {@link Matrix2d} and initialize it with the values from the given matrix.
+ *
+ * @param mat
+ * the matrix to initialize this matrix with
+ */
+ public Matrix2d(Matrix2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Create a new {@link Matrix2d} and make it a copy of the upper left 2x2 of the given {@link Matrix3dc}.
+ *
+ * @param mat
+ * the {@link Matrix3dc} to copy the values from
+ */
+ public Matrix2d(Matrix3dc mat) {
+ if (mat instanceof Matrix3d) {
+ MemUtil.INSTANCE.copy((Matrix3d) mat, this);
+ } else {
+ setMatrix3dc(mat);
+ }
+ }
+
+ /**
+ * Create a new {@link Matrix2d} and make it a copy of the upper left 2x2 of the given {@link Matrix3fc}.
+ *
+ * @param mat
+ * the {@link Matrix3fc} to copy the values from
+ */
+ public Matrix2d(Matrix3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Create a new 2x2 matrix using the supplied double values. The order of the parameter is column-major,
+ * so the first two parameters specify the two elements of the first column.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ */
+ public Matrix2d(double m00, double m01,
+ double m10, double m11) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ }
+
+ /**
+ * Create a new {@link Matrix2d} by reading its 4 double components from the given {@link DoubleBuffer}
+ * at the buffer's current position.
+ *
+ * That DoubleBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link DoubleBuffer} to read the matrix values from
+ */
+ public Matrix2d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Matrix2d} and initialize its two columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ */
+ public Matrix2d(Vector2dc col0, Vector2dc col1) {
+ m00 = col0.x();
+ m01 = col0.y();
+ m10 = col1.x();
+ m11 = col1.y();
+ }
+
+ public double m00() {
+ return m00;
+ }
+ public double m01() {
+ return m01;
+ }
+ public double m10() {
+ return m10;
+ }
+ public double m11() {
+ return m11;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix2d m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix2d m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix2d m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix2d m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix2d _m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix2d _m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix2d _m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix2d _m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the ones in m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix2d set(Matrix2dc m) {
+ if (m instanceof Matrix2d) {
+ MemUtil.INSTANCE.copy((Matrix2d) m, this);
+ } else {
+ setMatrix2dc(m);
+ }
+ return this;
+ }
+ private void setMatrix2dc(Matrix2dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Set the elements of this matrix to the ones in m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix2d set(Matrix2fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m10 = m.m10();
+ m11 = m.m11();
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the left 2x2 submatrix of m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix2d set(Matrix3x2dc m) {
+ if (m instanceof Matrix3x2d) {
+ MemUtil.INSTANCE.copy((Matrix3x2d) m, this);
+ } else {
+ setMatrix3x2dc(m);
+ }
+ return this;
+ }
+ private void setMatrix3x2dc(Matrix3x2dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Set the elements of this matrix to the left 2x2 submatrix of m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix2d set(Matrix3x2fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m10 = m.m10();
+ m11 = m.m11();
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the upper left 2x2 of the given {@link Matrix3dc}.
+ *
+ * @param m
+ * the {@link Matrix3dc} to copy the values from
+ * @return this
+ */
+ public Matrix2d set(Matrix3dc m) {
+ if (m instanceof Matrix3d) {
+ MemUtil.INSTANCE.copy((Matrix3d) m, this);
+ } else {
+ setMatrix3dc(m);
+ }
+ return this;
+ }
+ private void setMatrix3dc(Matrix3dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Set the elements of this matrix to the upper left 2x2 of the given {@link Matrix3dc}.
+ *
+ * @param m
+ * the {@link Matrix3fc} to copy the values from
+ * @return this
+ */
+ public Matrix2d set(Matrix3fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m10 = m.m10();
+ m11 = m.m11();
+ return this;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix2d mul(Matrix2dc right) {
+ return mul(right, this);
+ }
+
+ public Matrix2d mul(Matrix2dc right, Matrix2d dest) {
+ double nm00 = m00 * right.m00() + m10 * right.m01();
+ double nm01 = m01 * right.m00() + m11 * right.m01();
+ double nm10 = m00 * right.m10() + m10 * right.m11();
+ double nm11 = m01 * right.m10() + m11 * right.m11();
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix2d mul(Matrix2fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix2d mul(Matrix2fc right, Matrix2d dest) {
+ double nm00 = m00 * right.m00() + m10 * right.m01();
+ double nm01 = m01 * right.m00() + m11 * right.m01();
+ double nm10 = m00 * right.m10() + m10 * right.m11();
+ double nm11 = m01 * right.m10() + m11 * right.m11();
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix2d mulLocal(Matrix2dc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix2d mulLocal(Matrix2dc left, Matrix2d dest) {
+ double nm00 = left.m00() * m00 + left.m10() * m01;
+ double nm01 = left.m01() * m00 + left.m11() * m01;
+ double nm10 = left.m00() * m10 + left.m10() * m11;
+ double nm11 = left.m01() * m10 + left.m11() * m11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied double values. The result looks like this:
+ *
+ * m00, m10
+ * m01, m11
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @return this
+ */
+ public Matrix2d set(double m00, double m01,
+ double m10, double m11) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied double array. The result looks like this:
+ *
+ * 0, 2
+ * 1, 3
+ *
+ * This method only uses the first 4 values, all others are ignored.
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix2d set(double m[]) {
+ MemUtil.INSTANCE.copy(m, 0, this);
+ return this;
+ }
+
+ /**
+ * Set the two columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @return this
+ */
+ public Matrix2d set(Vector2dc col0, Vector2dc col1) {
+ m00 = col0.x();
+ m01 = col0.y();
+ m10 = col1.x();
+ m11 = col1.y();
+ return this;
+ }
+
+ public double determinant() {
+ return m00 * m11 - m10 * m01;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * @return this
+ */
+ public Matrix2d invert() {
+ return invert(this);
+ }
+
+ public Matrix2d invert(Matrix2d dest) {
+ double s = 1.0 / determinant();
+ double nm00 = m11 * s;
+ double nm01 = -m01 * s;
+ double nm10 = -m10 * s;
+ double nm11 = m00 * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this
+ */
+ public Matrix2d transpose() {
+ return transpose(this);
+ }
+
+ public Matrix2d transpose(Matrix2d dest) {
+ dest.set(m00, m10,
+ m01, m11);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix2dc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix2dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix2d get(Matrix2d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3x2d get(Matrix3x2d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3d get(Matrix3d dest) {
+ return dest.set(this);
+ }
+
+ public double getRotation() {
+ return (double) Math.atan2(m01, m11);
+ }
+
+
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer getTransposed(DoubleBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public DoubleBuffer getTransposed(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public Matrix2dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public double[] get(double[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ public double[] get(double[] arr) {
+ return get(arr, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+ /**
+ * Set the values of this matrix by reading 4 double values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set all values within this matrix to zero.
+ *
+ * @return this
+ */
+ public Matrix2d zero() {
+ MemUtil.INSTANCE.zero(this);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the identity.
+ *
+ * @return this
+ */
+ public Matrix2d identity() {
+ m00 = 1.0;
+ m01 = 0.0;
+ m10 = 0.0;
+ m11 = 1.0;
+ return this;
+ }
+
+ public Matrix2d scale(Vector2dc xy, Matrix2d dest) {
+ return scale(xy.x(), xy.y(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy.x
and
+ * xy.y
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @return this
+ */
+ public Matrix2d scale(Vector2dc xy) {
+ return scale(xy.x(), xy.y(), this);
+ }
+
+ public Matrix2d scale(double x, double y, Matrix2d dest) {
+ // scale matrix elements:
+ // m00 = x, m11 = y
+ // all others = 0
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x and
+ * y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix2d scale(double x, double y) {
+ return scale(x, y, this);
+ }
+
+ public Matrix2d scale(double xy, Matrix2d dest) {
+ return scale(xy, xy, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xy
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double)
+ *
+ * @param xy
+ * the factor for all components
+ * @return this
+ */
+ public Matrix2d scale(double xy) {
+ return scale(xy, xy);
+ }
+
+ public Matrix2d scaleLocal(double x, double y, Matrix2d dest) {
+ dest.m00 = x * m00;
+ dest.m01 = y * m01;
+ dest.m10 = x * m10;
+ dest.m11 = y * m11;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x and
+ * y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix2d scaleLocal(double x, double y) {
+ return scaleLocal(x, y, this);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(double) scale()} instead.
+ *
+ * @see #scale(double)
+ *
+ * @param factor
+ * the scale factor in x and y
+ * @return this
+ */
+ public Matrix2d scaling(double factor) {
+ MemUtil.INSTANCE.zero(this);
+ m00 = factor;
+ m11 = factor;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @return this
+ */
+ public Matrix2d scaling(double x, double y) {
+ MemUtil.INSTANCE.zero(this);
+ m00 = x;
+ m11 = y;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by xy.x
and xy.y
respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector2dc) scale()} instead.
+ *
+ * @see #scale(Vector2dc)
+ *
+ * @param xy
+ * the scale in x and y respectively
+ * @return this
+ */
+ public Matrix2d scaling(Vector2dc xy) {
+ return scaling(xy.x(), xy.y());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about the origin.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(double) rotate()} instead.
+ *
+ * @see #rotate(double)
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Matrix2d rotation(double angle) {
+ double sin = Math.sin(angle);
+ double cos = Math.cosFromSin(sin, angle);
+ m00 = cos;
+ m01 = sin;
+ m10 = -sin;
+ m11 = cos;
+ return this;
+ }
+
+ public Vector2d transform(Vector2d v) {
+ return v.mul(this);
+ }
+
+ public Vector2d transform(Vector2dc v, Vector2d dest) {
+ v.mul(this, dest);
+ return dest;
+ }
+
+ public Vector2d transform(double x, double y, Vector2d dest) {
+ dest.set(m00 * x + m10 * y,
+ m01 * x + m11 * y);
+ return dest;
+ }
+
+ public Vector2d transformTranspose(Vector2d v) {
+ return v.mulTranspose(this);
+ }
+
+ public Vector2d transformTranspose(Vector2dc v, Vector2d dest) {
+ v.mulTranspose(this, dest);
+ return dest;
+ }
+
+ public Vector2d transformTranspose(double x, double y, Vector2d dest) {
+ dest.set(m00 * x + m01 * y,
+ m10 * x + m11 * y);
+ return dest;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(m00);
+ out.writeDouble(m01);
+ out.writeDouble(m10);
+ out.writeDouble(m11);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readDouble();
+ m01 = in.readDouble();
+ m10 = in.readDouble();
+ m11 = in.readDouble();
+ }
+
+ /**
+ * Apply rotation about the origin to this matrix by rotating the given amount of radians.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Matrix2d rotate(double angle) {
+ return rotate(angle, this);
+ }
+
+ public Matrix2d rotate(double angle, Matrix2d dest) {
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ // rotation matrix elements:
+ // m00 = c, m01 = s, m10 = -s, m11 = c
+ double nm00 = m00 * c + m10 * s;
+ double nm01 = m01 * c + m11 * s;
+ double nm10 = m10 * c - m00 * s;
+ double nm11 = m11 * c - m01 * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the origin.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double)
+ *
+ * @param angle
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix2d rotateLocal(double angle) {
+ return rotateLocal(angle, this);
+ }
+
+ public Matrix2d rotateLocal(double angle, Matrix2d dest) {
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ // rotation matrix elements:
+ // m00 = c, m01 = s, m10 = -s, m11 = c
+ double nm00 = c * m00 - s * m01;
+ double nm01 = s * m00 + c * m01;
+ double nm10 = c * m10 - s * m11;
+ double nm11 = s * m10 + c * m11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ public Vector2d getRow(int row, Vector2d dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ dest.x = m00;
+ dest.y = m10;
+ break;
+ case 1:
+ dest.x = m01;
+ dest.y = m11;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..1]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..1]
+ */
+ public Matrix2d setRow(int row, Vector2dc src) throws IndexOutOfBoundsException {
+ return setRow(row, src.x(), src.y());
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..1]
+ * @param x
+ * the first element in the row
+ * @param y
+ * the second element in the row
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..1]
+ */
+ public Matrix2d setRow(int row, double x, double y) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ this.m00 = x;
+ this.m10 = y;
+ break;
+ case 1:
+ this.m01 = x;
+ this.m11 = y;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public Vector2d getColumn(int column, Vector2d dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ dest.x = m00;
+ dest.y = m01;
+ break;
+ case 1:
+ dest.x = m10;
+ dest.y = m11;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..1]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..1]
+ */
+ public Matrix2d setColumn(int column, Vector2dc src) throws IndexOutOfBoundsException {
+ return setColumn(column, src.x(), src.y());
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..1]
+ * @param x
+ * the first element in the column
+ * @param y
+ * the second element in the column
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..1]
+ */
+ public Matrix2d setColumn(int column, double x, double y) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ this.m00 = x;
+ this.m01 = y;
+ break;
+ case 1:
+ this.m10 = x;
+ this.m11 = y;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public double get(int column, int row) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m00;
+ case 1:
+ return m01;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m10;
+ case 1:
+ return m11;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ /**
+ * Set the matrix element at the given column and row to the specified value.
+ *
+ * @param column
+ * the colum index in [0..1]
+ * @param row
+ * the row index in [0..1]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix2d set(int column, int row, double value) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ this.m00 = value;
+ return this;
+ case 1:
+ this.m01 = value;
+ return this;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ this.m10 = value;
+ return this;
+ case 1:
+ this.m11 = value;
+ return this;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ /**
+ * Set this
matrix to its own normal matrix.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix2dc)} to set a given Matrix2d to this matrix.
+ *
+ * @see #set(Matrix2dc)
+ *
+ * @return this
+ */
+ public Matrix2d normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix2dc)} to set a given Matrix2d to this matrix.
+ *
+ * @see #set(Matrix2dc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix2d normal(Matrix2d dest) {
+ double det = m00 * m11 - m10 * m01;
+ double s = 1.0 / det;
+ /* Invert and transpose in one go */
+ double nm00 = m11 * s;
+ double nm01 = -m10 * s;
+ double nm10 = -m01 * s;
+ double nm11 = m00 * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ public Vector2d getScale(Vector2d dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11);
+ return dest;
+ }
+
+ public Vector2d positiveX(Vector2d dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = -m11;
+ dir.y = m01;
+ } else {
+ dir.x = m11;
+ dir.y = -m01;
+ }
+ return dir.normalize(dir);
+ }
+
+ public Vector2d normalizedPositiveX(Vector2d dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = -m11;
+ dir.y = m01;
+ } else {
+ dir.x = m11;
+ dir.y = -m01;
+ }
+ return dir;
+ }
+
+ public Vector2d positiveY(Vector2d dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = m10;
+ dir.y = -m00;
+ } else {
+ dir.x = -m10;
+ dir.y = m00;
+ }
+ return dir.normalize(dir);
+ }
+
+ public Vector2d normalizedPositiveY(Vector2d dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = m10;
+ dir.y = -m00;
+ } else {
+ dir.x = -m10;
+ dir.y = m00;
+ }
+ return dir;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(m00);
+ result = prime * result + (int) ((temp >>> 32) ^ temp);
+ temp = Double.doubleToLongBits(m01);
+ result = prime * result + (int) ((temp >>> 32) ^ temp);
+ temp = Double.doubleToLongBits(m10);
+ result = prime * result + (int) ((temp >>> 32) ^ temp);
+ temp = Double.doubleToLongBits(m11);
+ result = prime * result + (int) ((temp >>> 32) ^ temp);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Matrix2d other = (Matrix2d) obj;
+ if (Double.doubleToLongBits(m00) != Double.doubleToLongBits(other.m00))
+ return false;
+ if (Double.doubleToLongBits(m01) != Double.doubleToLongBits(other.m01))
+ return false;
+ if (Double.doubleToLongBits(m10) != Double.doubleToLongBits(other.m10))
+ return false;
+ if (Double.doubleToLongBits(m11) != Double.doubleToLongBits(other.m11))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix2dc m, double delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix2d))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ return true;
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix2d swap(Matrix2d other) {
+ MemUtil.INSTANCE.swap(this, other);
+ return this;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix2d add(Matrix2dc other) {
+ return add(other, this);
+ }
+
+ public Matrix2d add(Matrix2dc other, Matrix2d dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix2d sub(Matrix2dc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix2d sub(Matrix2dc other, Matrix2d dest) {
+ dest.m00 = m00 - other.m00();
+ dest.m01 = m01 - other.m01();
+ dest.m10 = m10 - other.m10();
+ dest.m11 = m11 - other.m11();
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix2d mulComponentWise(Matrix2dc other) {
+ return sub(other, this);
+ }
+
+ public Matrix2d mulComponentWise(Matrix2dc other, Matrix2d dest) {
+ dest.m00 = m00 * other.m00();
+ dest.m01 = m01 * other.m01();
+ dest.m10 = m10 * other.m10();
+ dest.m11 = m11 * other.m11();
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix2d lerp(Matrix2dc other, double t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix2d lerp(Matrix2dc other, double t, Matrix2d dest) {
+ dest.m00 = Math.fma(other.m00() - m00, t, m00);
+ dest.m01 = Math.fma(other.m01() - m01, t, m01);
+ dest.m10 = Math.fma(other.m10() - m10, t, m10);
+ dest.m11 = Math.fma(other.m11() - m11, t, m11);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) &&
+ Math.isFinite(m10) && Math.isFinite(m11);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2dc.java
new file mode 100644
index 000000000..f1888a0b6
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2dc.java
@@ -0,0 +1,725 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2020-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 2x2 matrix of double-precision floats.
+ *
+ * @author Joseph Burton
+ */
+public interface Matrix2dc {
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m01();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m11();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d mul(Matrix2dc right, Matrix2d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d mul(Matrix2fc right, Matrix2d dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix2d mulLocal(Matrix2dc left, Matrix2d dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ double determinant();
+
+ /**
+ * Invert the this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d invert(Matrix2d dest);
+
+ /**
+ * Transpose this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d transpose(Matrix2d dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix2d get(Matrix2d dest);
+
+ /**
+ * Get the current values of this
matrix and store them as
+ * the rotational component of dest
. All other values of dest
will
+ * be set to 0.
+ *
+ * @see Matrix3x2d#set(Matrix2dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3x2d get(Matrix3x2d dest);
+
+ /**
+ * Get the current values of this
matrix and store them as
+ * the rotational component of dest
. All other values of dest
will
+ * be set to identity.
+ *
+ * @see Matrix3d#set(Matrix2dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3d get(Matrix3d dest);
+
+ /**
+ * Get the angle of the rotation component of this
matrix.
+ *
+ * This method assumes that there is a valid rotation to be returned, i.e. that
+ * atan2(-m10, m00) == atan2(m01, m11)
.
+ *
+ * @return the angle
+ */
+ double getRotation();
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer getTransposed(DoubleBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer getTransposed(int index, DoubleBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix2dc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get(double[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(double[], int)}.
+ *
+ * @see #get(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get(double[] arr);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xy.x
and
+ * xy.y
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d scale(Vector2dc xy, Matrix2d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x and
+ * y factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d scale(double x, double y, Matrix2d dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xy
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, Matrix2d)
+ *
+ * @param xy
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d scale(double xy, Matrix2d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x and
+ * y factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d scaleLocal(double x, double y, Matrix2d dest);
+
+ /**
+ * Transform the given vector by this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector2d transform(Vector2d v);
+
+ /**
+ * Transform the given vector by this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transform(Vector2dc v, Vector2d dest);
+
+ /**
+ * Transform the vector (x, y)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transform(double x, double y, Vector2d dest);
+
+ /**
+ * Transform the given vector by the transpose of this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector2d transformTranspose(Vector2d v);
+
+ /**
+ * Transform the given vector by the transpose of this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transformTranspose(Vector2dc v, Vector2d dest);
+
+ /**
+ * Transform the vector (x, y)
by the transpose of this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transformTranspose(double x, double y, Vector2d dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d rotate(double ang, Matrix2d dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d rotateLocal(double ang, Matrix2d dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..1]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..1]
+ */
+ Vector2d getRow(int row, Vector2d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..1]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..1]
+ */
+ Vector2d getColumn(int column, Vector2d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the matrix element value at the given column and row.
+ *
+ * @param column
+ * the colum index in [0..1]
+ * @param row
+ * the row index in [0..1]
+ * @return the element value
+ */
+ double get(int column, int row);
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d normal(Matrix2d dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
and y
+ * @return dest
+ */
+ Vector2d getScale(Vector2d dest);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2d inv = new Matrix2d(this).invert();
+ * inv.transform(dir.set(1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector2d)} instead.
+ *
+ * @param dest
+ * will hold the direction of +X
+ * @return dest
+ */
+ Vector2d positiveX(Vector2d dest);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2d inv = new Matrix2d(this).transpose();
+ * inv.transform(dir.set(1, 0));
+ *
+ *
+ * @param dest
+ * will hold the direction of +X
+ * @return dest
+ */
+ Vector2d normalizedPositiveX(Vector2d dest);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2d inv = new Matrix2d(this).invert();
+ * inv.transform(dir.set(0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector2d)} instead.
+ *
+ * @param dest
+ * will hold the direction of +Y
+ * @return dest
+ */
+ Vector2d positiveY(Vector2d dest);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2d inv = new Matrix2d(this).transpose();
+ * inv.transform(dir.set(0, 1));
+ *
+ *
+ * @param dest
+ * will hold the direction of +Y
+ * @return dest
+ */
+ Vector2d normalizedPositiveY(Vector2d dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d add(Matrix2dc other, Matrix2d dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d sub(Matrix2dc subtrahend, Matrix2d dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d mulComponentWise(Matrix2dc other, Matrix2d dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2d lerp(Matrix2dc other, double t, Matrix2d dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix2dc m, double delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2f.java
new file mode 100644
index 000000000..46e3622c0
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2f.java
@@ -0,0 +1,1429 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2020-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a 2x2 matrix of floats, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10
+ * m01 m11
+ *
+ * @author Joseph Burton
+ */
+public class Matrix2f implements Externalizable, Cloneable, Matrix2fc {
+
+ private static final long serialVersionUID = 1L;
+
+ public float m00, m01;
+ public float m10, m11;
+
+ /**
+ * Create a new {@link Matrix2f} and set it to {@link #identity() identity}.
+ */
+ public Matrix2f() {
+ m00 = 1.0f;
+ m11 = 1.0f;
+ }
+
+ /**
+ * Create a new {@link Matrix2f} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix2fc} to copy the values from
+ */
+ public Matrix2f(Matrix2fc mat) {
+ if (mat instanceof Matrix2f) {
+ MemUtil.INSTANCE.copy((Matrix2f) mat, this);
+ } else {
+ setMatrix2fc(mat);
+ }
+ }
+
+ /**
+ * Create a new {@link Matrix2f} and make it a copy of the upper left 2x2 of the given {@link Matrix3fc}.
+ *
+ * @param mat
+ * the {@link Matrix3fc} to copy the values from
+ */
+ public Matrix2f(Matrix3fc mat) {
+ if (mat instanceof Matrix3f) {
+ MemUtil.INSTANCE.copy((Matrix3f) mat, this);
+ } else {
+ setMatrix3fc(mat);
+ }
+ }
+
+ /**
+ * Create a new 2x2 matrix using the supplied float values. The order of the parameter is column-major,
+ * so the first two parameters specify the two elements of the first column.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ */
+ public Matrix2f(float m00, float m01,
+ float m10, float m11) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ }
+
+ /**
+ * Create a new {@link Matrix2f} by reading its 4 float components from the given {@link FloatBuffer}
+ * at the buffer's current position.
+ *
+ * That FloatBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link FloatBuffer} to read the matrix values from
+ */
+ public Matrix2f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Matrix2f} and initialize its two columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ */
+ public Matrix2f(Vector2fc col0, Vector2fc col1) {
+ m00 = col0.x();
+ m01 = col0.y();
+ m10 = col1.x();
+ m11 = col1.y();
+ }
+
+ public float m00() {
+ return m00;
+ }
+ public float m01() {
+ return m01;
+ }
+ public float m10() {
+ return m10;
+ }
+ public float m11() {
+ return m11;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix2f m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix2f m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix2f m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix2f m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix2f _m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix2f _m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix2f _m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix2f _m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the ones in m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix2f set(Matrix2fc m) {
+ if (m instanceof Matrix2f) {
+ MemUtil.INSTANCE.copy((Matrix2f) m, this);
+ } else {
+ setMatrix2fc(m);
+ }
+ return this;
+ }
+ private void setMatrix2fc(Matrix2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Set the elements of this matrix to the left 2x2 submatrix of m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix2f set(Matrix3x2fc m) {
+ if (m instanceof Matrix3x2f) {
+ MemUtil.INSTANCE.copy((Matrix3x2f) m, this);
+ } else {
+ setMatrix3x2fc(m);
+ }
+ return this;
+ }
+ private void setMatrix3x2fc(Matrix3x2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Set the elements of this matrix to the upper left 2x2 of the given {@link Matrix3fc}.
+ *
+ * @param m
+ * the {@link Matrix3fc} to copy the values from
+ * @return this
+ */
+ public Matrix2f set(Matrix3fc m) {
+ if (m instanceof Matrix3f) {
+ MemUtil.INSTANCE.copy((Matrix3f) m, this);
+ } else {
+ setMatrix3fc(m);
+ }
+ return this;
+ }
+ private void setMatrix3fc(Matrix3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix2f mul(Matrix2fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix2f mul(Matrix2fc right, Matrix2f dest) {
+ float nm00 = m00 * right.m00() + m10 * right.m01();
+ float nm01 = m01 * right.m00() + m11 * right.m01();
+ float nm10 = m00 * right.m10() + m10 * right.m11();
+ float nm11 = m01 * right.m10() + m11 * right.m11();
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix2f mulLocal(Matrix2fc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix2f mulLocal(Matrix2fc left, Matrix2f dest) {
+ float nm00 = left.m00() * m00 + left.m10() * m01;
+ float nm01 = left.m01() * m00 + left.m11() * m01;
+ float nm10 = left.m00() * m10 + left.m10() * m11;
+ float nm11 = left.m01() * m10 + left.m11() * m11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied float values. The result looks like this:
+ *
+ * m00, m10
+ * m01, m11
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @return this
+ */
+ public Matrix2f set(float m00, float m01,
+ float m10, float m11) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied float array. The result looks like this:
+ *
+ * 0, 2
+ * 1, 3
+ *
+ * This method only uses the first 4 values, all others are ignored.
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix2f set(float m[]) {
+ MemUtil.INSTANCE.copy(m, 0, this);
+ return this;
+ }
+
+ /**
+ * Set the two columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @return this
+ */
+ public Matrix2f set(Vector2fc col0, Vector2fc col1) {
+ m00 = col0.x();
+ m01 = col0.y();
+ m10 = col1.x();
+ m11 = col1.y();
+ return this;
+ }
+
+ public float determinant() {
+ return m00 * m11 - m10 * m01;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * @return this
+ */
+ public Matrix2f invert() {
+ return invert(this);
+ }
+
+ public Matrix2f invert(Matrix2f dest) {
+ float s = 1.0f / determinant();
+ float nm00 = m11 * s;
+ float nm01 = -m01 * s;
+ float nm10 = -m10 * s;
+ float nm11 = m00 * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this
+ */
+ public Matrix2f transpose() {
+ return transpose(this);
+ }
+
+ public Matrix2f transpose(Matrix2f dest) {
+ dest.set(m00, m10,
+ m01, m11);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix2fc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix2fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix2f get(Matrix2f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3x2f get(Matrix3x2f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3f get(Matrix3f dest) {
+ return dest.set(this);
+ }
+
+ public float getRotation() {
+ return Math.atan2(m01, m11);
+ }
+
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer getTransposed(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public FloatBuffer getTransposed(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+ public Matrix2fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public float[] get(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ public float[] get(float[] arr) {
+ return get(arr, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 4 float values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix2f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set all values within this matrix to zero.
+ *
+ * @return this
+ */
+ public Matrix2f zero() {
+ MemUtil.INSTANCE.zero(this);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the identity.
+ *
+ * @return this
+ */
+ public Matrix2f identity() {
+ MemUtil.INSTANCE.identity(this);
+ return this;
+ }
+
+ public Matrix2f scale(Vector2fc xy, Matrix2f dest) {
+ return scale(xy.x(), xy.y(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy.x
and
+ * xy.y
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @return this
+ */
+ public Matrix2f scale(Vector2fc xy) {
+ return scale(xy.x(), xy.y(), this);
+ }
+
+ public Matrix2f scale(float x, float y, Matrix2f dest) {
+ // scale matrix elements:
+ // m00 = x, m11 = y
+ // all others = 0
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x and
+ * y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix2f scale(float x, float y) {
+ return scale(x, y, this);
+ }
+
+ public Matrix2f scale(float xy, Matrix2f dest) {
+ return scale(xy, xy, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xy
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(float, float)
+ *
+ * @param xy
+ * the factor for all components
+ * @return this
+ */
+ public Matrix2f scale(float xy) {
+ return scale(xy, xy);
+ }
+
+ public Matrix2f scaleLocal(float x, float y, Matrix2f dest) {
+ dest.m00 = x * m00;
+ dest.m01 = y * m01;
+ dest.m10 = x * m10;
+ dest.m11 = y * m11;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x and
+ * y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix2f scaleLocal(float x, float y) {
+ return scaleLocal(x, y, this);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(float) scale()} instead.
+ *
+ * @see #scale(float)
+ *
+ * @param factor
+ * the scale factor in x and y
+ * @return this
+ */
+ public Matrix2f scaling(float factor) {
+ MemUtil.INSTANCE.zero(this);
+ m00 = factor;
+ m11 = factor;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @return this
+ */
+ public Matrix2f scaling(float x, float y) {
+ MemUtil.INSTANCE.zero(this);
+ m00 = x;
+ m11 = y;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by xy.x
and xy.y
respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector2fc) scale()} instead.
+ *
+ * @see #scale(Vector2fc)
+ *
+ * @param xy
+ * the scale in x and y respectively
+ * @return this
+ */
+ public Matrix2f scaling(Vector2fc xy) {
+ return scaling(xy.x(), xy.y());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about the origin.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(float) rotate()} instead.
+ *
+ * @see #rotate(float)
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Matrix2f rotation(float angle) {
+ float sin = Math.sin(angle);
+ float cos = Math.cosFromSin(sin, angle);
+ m00 = cos;
+ m01 = sin;
+ m10 = -sin;
+ m11 = cos;
+ return this;
+ }
+
+ public Vector2f transform(Vector2f v) {
+ return v.mul(this);
+ }
+
+ public Vector2f transform(Vector2fc v, Vector2f dest) {
+ v.mul(this, dest);
+ return dest;
+ }
+
+ public Vector2f transform(float x, float y, Vector2f dest) {
+ dest.set(m00 * x + m10 * y,
+ m01 * x + m11 * y);
+ return dest;
+ }
+
+ public Vector2f transformTranspose(Vector2f v) {
+ return v.mulTranspose(this);
+ }
+
+ public Vector2f transformTranspose(Vector2fc v, Vector2f dest) {
+ v.mulTranspose(this, dest);
+ return dest;
+ }
+
+ public Vector2f transformTranspose(float x, float y, Vector2f dest) {
+ dest.set(m00 * x + m01 * y,
+ m10 * x + m11 * y);
+ return dest;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(m00);
+ out.writeFloat(m01);
+ out.writeFloat(m10);
+ out.writeFloat(m11);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readFloat();
+ m01 = in.readFloat();
+ m10 = in.readFloat();
+ m11 = in.readFloat();
+ }
+
+ /**
+ * Apply rotation about the origin to this matrix by rotating the given amount of radians.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Matrix2f rotate(float angle) {
+ return rotate(angle, this);
+ }
+
+ public Matrix2f rotate(float angle, Matrix2f dest) {
+ float s = Math.sin(angle);
+ float c = Math.cosFromSin(s, angle);
+ // rotation matrix elements:
+ // m00 = c, m01 = s, m10 = -s, m11 = c
+ float nm00 = m00 * c + m10 * s;
+ float nm01 = m01 * c + m11 * s;
+ float nm10 = m10 * c - m00 * s;
+ float nm11 = m11 * c - m01 * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the origin.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float)
+ *
+ * @param angle
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix2f rotateLocal(float angle) {
+ return rotateLocal(angle, this);
+ }
+
+ public Matrix2f rotateLocal(float angle, Matrix2f dest) {
+ float s = Math.sin(angle);
+ float c = Math.cosFromSin(s, angle);
+ // rotation matrix elements:
+ // m00 = c, m01 = s, m10 = -s, m11 = c
+ float nm00 = c * m00 - s * m01;
+ float nm01 = s * m00 + c * m01;
+ float nm10 = c * m10 - s * m11;
+ float nm11 = s * m10 + c * m11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ public Vector2f getRow(int row, Vector2f dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ dest.x = m00;
+ dest.y = m10;
+ break;
+ case 1:
+ dest.x = m01;
+ dest.y = m11;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..1]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..1]
+ */
+ public Matrix2f setRow(int row, Vector2fc src) throws IndexOutOfBoundsException {
+ return setRow(row, src.x(), src.y());
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..1]
+ * @param x
+ * the first element in the row
+ * @param y
+ * the second element in the row
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..1]
+ */
+ public Matrix2f setRow(int row, float x, float y) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ this.m00 = x;
+ this.m10 = y;
+ break;
+ case 1:
+ this.m01 = x;
+ this.m11 = y;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public Vector2f getColumn(int column, Vector2f dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ dest.x = m00;
+ dest.y = m01;
+ break;
+ case 1:
+ dest.x = m10;
+ dest.y = m11;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..1]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..1]
+ */
+ public Matrix2f setColumn(int column, Vector2fc src) throws IndexOutOfBoundsException {
+ return setColumn(column, src.x(), src.y());
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..1]
+ * @param x
+ * the first element in the column
+ * @param y
+ * the second element in the column
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..1]
+ */
+ public Matrix2f setColumn(int column, float x, float y) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ this.m00 = x;
+ this.m01 = y;
+ break;
+ case 1:
+ this.m10 = x;
+ this.m11 = y;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public float get(int column, int row) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m00;
+ case 1:
+ return m01;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m10;
+ case 1:
+ return m11;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ /**
+ * Set the matrix element at the given column and row to the specified value.
+ *
+ * @param column
+ * the colum index in [0..1]
+ * @param row
+ * the row index in [0..1]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix2f set(int column, int row, float value) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ this.m00 = value;
+ return this;
+ case 1:
+ this.m01 = value;
+ return this;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ this.m10 = value;
+ return this;
+ case 1:
+ this.m11 = value;
+ return this;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ /**
+ * Set this
matrix to its own normal matrix.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix2fc)} to set a given Matrix2f to this matrix.
+ *
+ * @see #set(Matrix2fc)
+ *
+ * @return this
+ */
+ public Matrix2f normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix2fc)} to set a given Matrix2f to this matrix.
+ *
+ * @see #set(Matrix2fc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix2f normal(Matrix2f dest) {
+ float det = m00 * m11 - m10 * m01;
+ float s = 1.0f / det;
+ /* Invert and transpose in one go */
+ float nm00 = m11 * s;
+ float nm01 = -m10 * s;
+ float nm10 = -m01 * s;
+ float nm11 = m00 * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ return dest;
+ }
+
+ public Vector2f getScale(Vector2f dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11);
+ return dest;
+ }
+
+ public Vector2f positiveX(Vector2f dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = -m11;
+ dir.y = m01;
+ } else {
+ dir.x = m11;
+ dir.y = -m01;
+ }
+ return dir.normalize(dir);
+ }
+
+ public Vector2f normalizedPositiveX(Vector2f dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = -m11;
+ dir.y = m01;
+ } else {
+ dir.x = m11;
+ dir.y = -m01;
+ }
+ return dir;
+ }
+
+ public Vector2f positiveY(Vector2f dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = m10;
+ dir.y = -m00;
+ } else {
+ dir.x = -m10;
+ dir.y = m00;
+ }
+ return dir.normalize(dir);
+ }
+
+ public Vector2f normalizedPositiveY(Vector2f dir) {
+ if (m00 * m11 < m01 * m10) { // negative determinant?
+ dir.x = m10;
+ dir.y = -m00;
+ } else {
+ dir.x = -m10;
+ dir.y = m00;
+ }
+ return dir;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(m00);
+ result = prime * result + Float.floatToIntBits(m01);
+ result = prime * result + Float.floatToIntBits(m10);
+ result = prime * result + Float.floatToIntBits(m11);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Matrix2f other = (Matrix2f) obj;
+ if (Float.floatToIntBits(m00) != Float.floatToIntBits(other.m00))
+ return false;
+ if (Float.floatToIntBits(m01) != Float.floatToIntBits(other.m01))
+ return false;
+ if (Float.floatToIntBits(m10) != Float.floatToIntBits(other.m10))
+ return false;
+ if (Float.floatToIntBits(m11) != Float.floatToIntBits(other.m11))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix2fc m, float delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix2f))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ return true;
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix2f swap(Matrix2f other) {
+ MemUtil.INSTANCE.swap(this, other);
+ return this;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix2f add(Matrix2fc other) {
+ return add(other, this);
+ }
+
+ public Matrix2f add(Matrix2fc other, Matrix2f dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix2f sub(Matrix2fc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix2f sub(Matrix2fc other, Matrix2f dest) {
+ dest.m00 = m00 - other.m00();
+ dest.m01 = m01 - other.m01();
+ dest.m10 = m10 - other.m10();
+ dest.m11 = m11 - other.m11();
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix2f mulComponentWise(Matrix2fc other) {
+ return sub(other, this);
+ }
+
+ public Matrix2f mulComponentWise(Matrix2fc other, Matrix2f dest) {
+ dest.m00 = m00 * other.m00();
+ dest.m01 = m01 * other.m01();
+ dest.m10 = m10 * other.m10();
+ dest.m11 = m11 * other.m11();
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix2f lerp(Matrix2fc other, float t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix2f lerp(Matrix2fc other, float t, Matrix2f dest) {
+ dest.m00 = Math.fma(other.m00() - m00, t, m00);
+ dest.m01 = Math.fma(other.m01() - m01, t, m01);
+ dest.m10 = Math.fma(other.m10() - m10, t, m10);
+ dest.m11 = Math.fma(other.m11() - m11, t, m11);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) &&
+ Math.isFinite(m10) && Math.isFinite(m11);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2fc.java
new file mode 100644
index 000000000..3b8c21e9d
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix2fc.java
@@ -0,0 +1,709 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2020-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 2x2 matrix of single-precision floats.
+ *
+ * @author Joseph Burton
+ */
+public interface Matrix2fc {
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m01();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m11();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f mul(Matrix2fc right, Matrix2f dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix2f mulLocal(Matrix2fc left, Matrix2f dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ float determinant();
+
+ /**
+ * Invert the this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f invert(Matrix2f dest);
+
+ /**
+ * Transpose this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f transpose(Matrix2f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix2f get(Matrix2f dest);
+
+ /**
+ * Get the current values of this
matrix and store them as
+ * the rotational component of dest
. All other values of dest
will
+ * be set to 0.
+ *
+ * @see Matrix3x2f#set(Matrix2fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3x2f get(Matrix3x2f dest);
+
+ /**
+ * Get the current values of this
matrix and store them as
+ * the rotational component of dest
. All other values of dest
will
+ * be set to identity.
+ *
+ * @see Matrix3f#set(Matrix2fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3f get(Matrix3f dest);
+
+ /**
+ * Get the angle of the rotation component of this
matrix.
+ *
+ * This method assumes that there is a valid rotation to be returned, i.e. that
+ * atan2(-m10, m00) == atan2(m01, m11)
.
+ *
+ * @return the angle
+ */
+ float getRotation();
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(FloatBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(int index, FloatBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix2fc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xy.x
and
+ * xy.y
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f scale(Vector2fc xy, Matrix2f dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x and
+ * y factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f scale(float x, float y, Matrix2f dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xy
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(float, float, Matrix2f)
+ *
+ * @param xy
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f scale(float xy, Matrix2f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x and
+ * y factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f scaleLocal(float x, float y, Matrix2f dest);
+
+ /**
+ * Transform the given vector by this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector2f transform(Vector2f v);
+
+ /**
+ * Transform the given vector by this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transform(Vector2fc v, Vector2f dest);
+
+ /**
+ * Transform the vector (x, y)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transform(float x, float y, Vector2f dest);
+
+ /**
+ * Transform the given vector by the transpose of this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector2f transformTranspose(Vector2f v);
+
+ /**
+ * Transform the given vector by the transpose of this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transformTranspose(Vector2fc v, Vector2f dest);
+
+ /**
+ * Transform the vector (x, y)
by the transpose of this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transformTranspose(float x, float y, Vector2f dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f rotate(float ang, Matrix2f dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * The produced rotation will rotate a vector counter-clockwise around the origin.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f rotateLocal(float ang, Matrix2f dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..1]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..1]
+ */
+ Vector2f getRow(int row, Vector2f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..1]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..1]
+ */
+ Vector2f getColumn(int column, Vector2f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the matrix element value at the given column and row.
+ *
+ * @param column
+ * the colum index in [0..1]
+ * @param row
+ * the row index in [0..1]
+ * @return the element value
+ */
+ float get(int column, int row);
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f normal(Matrix2f dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
and y
+ * @return dest
+ */
+ Vector2f getScale(Vector2f dest);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2f inv = new Matrix2f(this).invert();
+ * inv.transform(dir.set(1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector2f)} instead.
+ *
+ * @param dest
+ * will hold the direction of +X
+ * @return dest
+ */
+ Vector2f positiveX(Vector2f dest);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2f inv = new Matrix2f(this).transpose();
+ * inv.transform(dir.set(1, 0));
+ *
+ *
+ * @param dest
+ * will hold the direction of +X
+ * @return dest
+ */
+ Vector2f normalizedPositiveX(Vector2f dest);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2f inv = new Matrix2f(this).invert();
+ * inv.transform(dir.set(0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector2f)} instead.
+ *
+ * @param dest
+ * will hold the direction of +Y
+ * @return dest
+ */
+ Vector2f positiveY(Vector2f dest);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix2f inv = new Matrix2f(this).transpose();
+ * inv.transform(dir.set(0, 1));
+ *
+ *
+ * @param dest
+ * will hold the direction of +Y
+ * @return dest
+ */
+ Vector2f normalizedPositiveY(Vector2f dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f add(Matrix2fc other, Matrix2f dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f sub(Matrix2fc subtrahend, Matrix2f dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f mulComponentWise(Matrix2fc other, Matrix2f dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix2f lerp(Matrix2fc other, float t, Matrix2f dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix2fc m, float delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3d.java
new file mode 100644
index 000000000..97fddc563
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3d.java
@@ -0,0 +1,5582 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a 3x3 matrix of doubles, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20
+ * m01 m11 m21
+ * m02 m12 m22
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Matrix3d implements Externalizable, Cloneable, Matrix3dc {
+
+ private static final long serialVersionUID = 1L;
+
+ public double m00, m01, m02;
+ public double m10, m11, m12;
+ public double m20, m21, m22;
+
+ /**
+ * Create a new {@link Matrix3d} and initialize it to {@link #identity() identity}.
+ */
+ public Matrix3d() {
+ m00 = 1.0;
+ m11 = 1.0;
+ m22 = 1.0;
+ }
+
+ /**
+ * Create a new {@link Matrix3d} by setting its uppper left 2x2 submatrix to the values of the given {@link Matrix2dc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix2dc}
+ */
+ public Matrix3d(Matrix2dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} by setting its uppper left 2x2 submatrix to the values of the given {@link Matrix2fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix2fc}
+ */
+ public Matrix3d(Matrix2fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} and initialize it with the values from the given matrix.
+ *
+ * @param mat
+ * the matrix to initialize this matrix with
+ */
+ public Matrix3d(Matrix3dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} and initialize it with the values from the given matrix.
+ *
+ * @param mat
+ * the matrix to initialize this matrix with
+ */
+ public Matrix3d(Matrix3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} and make it a copy of the upper left 3x3 of the given {@link Matrix4fc}.
+ *
+ * @param mat
+ * the {@link Matrix4fc} to copy the values from
+ */
+ public Matrix3d(Matrix4fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} and make it a copy of the upper left 3x3 of the given {@link Matrix4dc}.
+ *
+ * @param mat
+ * the {@link Matrix4dc} to copy the values from
+ */
+ public Matrix3d(Matrix4dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} and initialize its elements with the given values.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m02
+ * the value of m02
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m12
+ * the value of m12
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ * @param m22
+ * the value of m22
+ */
+ public Matrix3d(double m00, double m01, double m02,
+ double m10, double m11, double m12,
+ double m20, double m21, double m22) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ }
+
+ /**
+ * Create a new {@link Matrix3d} by reading its 9 double components from the given {@link DoubleBuffer}
+ * at the buffer's current position.
+ *
+ * That DoubleBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link DoubleBuffer} to read the matrix values from
+ */
+ public Matrix3d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Matrix3d} and initialize its three columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ */
+ public Matrix3d(Vector3dc col0, Vector3dc col1, Vector3dc col2) {
+ set(col0, col1, col2);
+ }
+
+ public double m00() {
+ return m00;
+ }
+ public double m01() {
+ return m01;
+ }
+ public double m02() {
+ return m02;
+ }
+ public double m10() {
+ return m10;
+ }
+ public double m11() {
+ return m11;
+ }
+ public double m12() {
+ return m12;
+ }
+ public double m20() {
+ return m20;
+ }
+ public double m21() {
+ return m21;
+ }
+ public double m22() {
+ return m22;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix3d m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix3d m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ public Matrix3d m02(double m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix3d m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix3d m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ public Matrix3d m12(double m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ public Matrix3d m20(double m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ public Matrix3d m21(double m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ public Matrix3d m22(double m22) {
+ this.m22 = m22;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix3d _m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix3d _m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ Matrix3d _m02(double m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix3d _m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix3d _m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ Matrix3d _m12(double m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix3d _m20(double m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix3d _m21(double m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ Matrix3d _m22(double m22) {
+ this.m22 = m22;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix to the ones in m.
+ *
+ * @param m
+ * the matrix whose values will be copied
+ * @return this
+ */
+ public Matrix3d set(Matrix3dc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ return this;
+ }
+
+ /**
+ * Store the values of the transpose of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the transposed values from
+ * @return this
+ */
+ public Matrix3d setTransposed(Matrix3dc m) {
+ double nm10 = m.m01(), nm12 = m.m21();
+ double nm20 = m.m02(), nm21 = m.m12();
+ return this
+ ._m00(m.m00())._m01(m.m10())._m02(m.m20())
+ ._m10(nm10)._m11(m.m11())._m12(nm12)
+ ._m20(nm20)._m21(nm21)._m22(m.m22());
+ }
+
+ /**
+ * Set the values in this matrix to the ones in m.
+ *
+ * @param m
+ * the matrix whose values will be copied
+ * @return this
+ */
+ public Matrix3d set(Matrix3fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ return this;
+ }
+
+ /**
+ * Store the values of the transpose of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the transposed values from
+ * @return this
+ */
+ public Matrix3d setTransposed(Matrix3fc m) {
+ float nm10 = m.m01(), nm12 = m.m21();
+ float nm20 = m.m02(), nm21 = m.m12();
+ return this
+ ._m00(m.m00())._m01(m.m10())._m02(m.m20())
+ ._m10(nm10)._m11(m.m11())._m12(nm12)
+ ._m20(nm20)._m21(nm21)._m22(m.m22());
+ }
+
+ /**
+ * Set the elements of this matrix to the left 3x3 submatrix of m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix3d set(Matrix4x3dc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the upper left 3x3 of the given {@link Matrix4fc}.
+ *
+ * @param mat
+ * the {@link Matrix4fc} to copy the values from
+ * @return this
+ */
+ public Matrix3d set(Matrix4fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the upper left 3x3 of the given {@link Matrix4dc}.
+ *
+ * @param mat
+ * the {@link Matrix4dc} to copy the values from
+ * @return this
+ */
+ public Matrix3d set(Matrix4dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ return this;
+ }
+
+ /**
+ * Set the upper left 2x2 submatrix of this {@link Matrix3d} to the given {@link Matrix2fc}
+ * and the rest to identity.
+ *
+ * @see #Matrix3d(Matrix2fc)
+ *
+ * @param mat
+ * the {@link Matrix2fc}
+ * @return this
+ */
+ public Matrix3d set(Matrix2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = 0.0;
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ return this;
+ }
+
+ /**
+ * Set the upper left 2x2 submatrix of this {@link Matrix3d} to the given {@link Matrix2dc}
+ * and the rest to identity.
+ *
+ * @see #Matrix3d(Matrix2dc)
+ *
+ * @param mat
+ * the {@link Matrix2dc}
+ * @return this
+ */
+ public Matrix3d set(Matrix2dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = 0.0;
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Matrix3d set(AxisAngle4f axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ m00 = c + x*x*omc;
+ m11 = c + y*y*omc;
+ m22 = c + z*z*omc;
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ m10 = tmp1 - tmp2;
+ m01 = tmp1 + tmp2;
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = tmp1 + tmp2;
+ m02 = tmp1 - tmp2;
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = tmp1 - tmp2;
+ m12 = tmp1 + tmp2;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Matrix3d set(AxisAngle4d axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ m00 = c + x*x*omc;
+ m11 = c + y*y*omc;
+ m22 = c + z*z*omc;
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ m10 = tmp1 - tmp2;
+ m01 = tmp1 + tmp2;
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = tmp1 + tmp2;
+ m02 = tmp1 - tmp2;
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = tmp1 - tmp2;
+ m12 = tmp1 + tmp2;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation - and possibly scaling - equivalent to the given quaternion.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param q
+ * the quaternion
+ * @return this
+ */
+ public Matrix3d set(Quaternionfc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Set this matrix to a rotation - and possibly scaling - equivalent to the given quaternion.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param q
+ * the quaternion
+ * @return this
+ */
+ public Matrix3d set(Quaterniondc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Multiply this matrix by the supplied matrix.
+ * This matrix will be the left one.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand
+ * @return this
+ */
+ public Matrix3d mul(Matrix3dc right) {
+ return mul(right, this);
+ }
+
+ public Matrix3d mul(Matrix3dc right, Matrix3d dest) {
+ double nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ double nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ double nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ double nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ double nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ double nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ double nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ double nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ double nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3d mulLocal(Matrix3dc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix3d mulLocal(Matrix3dc left, Matrix3d dest) {
+ double nm00 = left.m00() * m00 + left.m10() * m01 + left.m20() * m02;
+ double nm01 = left.m01() * m00 + left.m11() * m01 + left.m21() * m02;
+ double nm02 = left.m02() * m00 + left.m12() * m01 + left.m22() * m02;
+ double nm10 = left.m00() * m10 + left.m10() * m11 + left.m20() * m12;
+ double nm11 = left.m01() * m10 + left.m11() * m11 + left.m21() * m12;
+ double nm12 = left.m02() * m10 + left.m12() * m11 + left.m22() * m12;
+ double nm20 = left.m00() * m20 + left.m10() * m21 + left.m20() * m22;
+ double nm21 = left.m01() * m20 + left.m11() * m21 + left.m21() * m22;
+ double nm22 = left.m02() * m20 + left.m12() * m21 + left.m22() * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied matrix.
+ * This matrix will be the left one.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand
+ * @return this
+ */
+ public Matrix3d mul(Matrix3fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix3d mul(Matrix3fc right, Matrix3d dest) {
+ double nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ double nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ double nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ double nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ double nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ double nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ double nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ double nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ double nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied double values. The result looks like this:
+ *
+ * m00, m10, m20
+ * m01, m11, m21
+ * m02, m12, m22
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m02
+ * the new value of m02
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m12
+ * the new value of m12
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @param m22
+ * the new value of m22
+ * @return this
+ */
+ public Matrix3d set(double m00, double m01, double m02,
+ double m10, double m11, double m12,
+ double m20, double m21, double m22) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied double array. The result looks like this:
+ *
+ * 0, 3, 6
+ * 1, 4, 7
+ * 2, 5, 8
+ *
+ * Only uses the first 9 values, all others are ignored.
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix3d set(double m[]) {
+ m00 = m[0];
+ m01 = m[1];
+ m02 = m[2];
+ m10 = m[3];
+ m11 = m[4];
+ m12 = m[5];
+ m20 = m[6];
+ m21 = m[7];
+ m22 = m[8];
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied double array. The result looks like this:
+ *
+ * 0, 3, 6
+ * 1, 4, 7
+ * 2, 5, 8
+ *
+ * Only uses the first 9 values, all others are ignored
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix3d set(float m[]) {
+ m00 = m[0];
+ m01 = m[1];
+ m02 = m[2];
+ m10 = m[3];
+ m11 = m[4];
+ m12 = m[5];
+ m20 = m[6];
+ m21 = m[7];
+ m22 = m[8];
+ return this;
+ }
+
+ public double determinant() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * @return this
+ */
+ public Matrix3d invert() {
+ return invert(this);
+ }
+
+ public Matrix3d invert(Matrix3d dest) {
+ double a = Math.fma(m00, m11, -m01 * m10);
+ double b = Math.fma(m02, m10, -m00 * m12);
+ double c = Math.fma(m01, m12, -m02 * m11);
+ double d = Math.fma(a, m22, Math.fma(b, m21, c * m20));
+ double s = 1.0 / d;
+ double nm00 = Math.fma(m11, m22, -m21 * m12) * s;
+ double nm01 = Math.fma(m21, m02, -m01 * m22) * s;
+ double nm02 = c * s;
+ double nm10 = Math.fma(m20, m12, -m10 * m22) * s;
+ double nm11 = Math.fma(m00, m22, -m20 * m02) * s;
+ double nm12 = b * s;
+ double nm20 = Math.fma(m10, m21, -m20 * m11) * s;
+ double nm21 = Math.fma(m20, m01, -m00 * m21) * s;
+ double nm22 = a * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this
+ */
+ public Matrix3d transpose() {
+ return transpose(this);
+ }
+
+ public Matrix3d transpose(Matrix3d dest) {
+ dest.set(m00, m10, m20,
+ m01, m11, m21,
+ m02, m12, m22);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + "\n"
+ + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix3dc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix3dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix3d get(Matrix3d dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4f getRotation(AxisAngle4f dest) {
+ return dest.set(this);
+ }
+
+ public Quaternionf getUnnormalizedRotation(Quaternionf dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaternionf getNormalizedRotation(Quaternionf dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaterniond getNormalizedRotation(Quaterniond dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getFloats(ByteBuffer buffer) {
+ return getFloats(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getFloats(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, index, buffer);
+ return buffer;
+ }
+
+ public Matrix3dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public double[] get(double[] arr, int offset) {
+ arr[offset+0] = m00;
+ arr[offset+1] = m01;
+ arr[offset+2] = m02;
+ arr[offset+3] = m10;
+ arr[offset+4] = m11;
+ arr[offset+5] = m12;
+ arr[offset+6] = m20;
+ arr[offset+7] = m21;
+ arr[offset+8] = m22;
+ return arr;
+ }
+
+ public double[] get(double[] arr) {
+ return get(arr, 0);
+ }
+
+ public float[] get(float[] arr, int offset) {
+ arr[offset+0] = (float)m00;
+ arr[offset+1] = (float)m01;
+ arr[offset+2] = (float)m02;
+ arr[offset+3] = (float)m10;
+ arr[offset+4] = (float)m11;
+ arr[offset+5] = (float)m12;
+ arr[offset+6] = (float)m20;
+ arr[offset+7] = (float)m21;
+ arr[offset+8] = (float)m22;
+ return arr;
+ }
+
+ public float[] get(float[] arr) {
+ return get(arr, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d setFloats(ByteBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d setFloats(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, index, buffer);
+ return this;
+ }
+ /**
+ * Set the values of this matrix by reading 9 double values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set the three columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @return this
+ */
+ public Matrix3d set(Vector3dc col0,
+ Vector3dc col1,
+ Vector3dc col2) {
+ this.m00 = col0.x();
+ this.m01 = col0.y();
+ this.m02 = col0.z();
+ this.m10 = col1.x();
+ this.m11 = col1.y();
+ this.m12 = col1.z();
+ this.m20 = col2.x();
+ this.m21 = col2.y();
+ this.m22 = col2.z();
+ return this;
+ }
+
+ /**
+ * Set all the values within this matrix to 0.
+ *
+ * @return this
+ */
+ public Matrix3d zero() {
+ m00 = 0.0;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 0.0;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 0.0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to the identity.
+ *
+ * @return this
+ */
+ public Matrix3d identity() {
+ m00 = 1.0;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 1.0;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(double) scale()} instead.
+ *
+ * @see #scale(double)
+ *
+ * @param factor
+ * the scale factor in x, y and z
+ * @return this
+ */
+ public Matrix3d scaling(double factor) {
+ m00 = factor;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = factor;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = factor;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @param z
+ * the scale in z
+ * @return this
+ */
+ public Matrix3d scaling(double x, double y, double z) {
+ m00 = x;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = y;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = z;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by xyz.x
, xyz.y
and xyz.z
respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector3dc) scale()} instead.
+ *
+ * @see #scale(Vector3dc)
+ *
+ * @param xyz
+ * the scale in x, y and z respectively
+ * @return this
+ */
+ public Matrix3d scaling(Vector3dc xyz) {
+ m00 = xyz.x();
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = xyz.y();
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = xyz.z();
+ return this;
+ }
+
+ public Matrix3d scale(Vector3dc xyz, Matrix3d dest) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @return this
+ */
+ public Matrix3d scale(Vector3dc xyz) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), this);
+ }
+
+ public Matrix3d scale(double x, double y, double z, Matrix3d dest) {
+ // scale matrix elements:
+ // m00 = x, m11 = y, m22 = z
+ // all others = 0
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m02 = m02 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ dest.m12 = m12 * y;
+ dest.m20 = m20 * z;
+ dest.m21 = m21 * z;
+ dest.m22 = m22 * z;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix3d scale(double x, double y, double z) {
+ return scale(x, y, z, this);
+ }
+
+ public Matrix3d scale(double xyz, Matrix3d dest) {
+ return scale(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, double)
+ *
+ * @param xyz
+ * the factor for all components
+ * @return this
+ */
+ public Matrix3d scale(double xyz) {
+ return scale(xyz, xyz, xyz);
+ }
+
+ public Matrix3d scaleLocal(double x, double y, double z, Matrix3d dest) {
+ double nm00 = x * m00;
+ double nm01 = y * m01;
+ double nm02 = z * m02;
+ double nm10 = x * m10;
+ double nm11 = y * m11;
+ double nm12 = z * m12;
+ double nm20 = x * m20;
+ double nm21 = y * m21;
+ double nm22 = z * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix3d scaleLocal(double x, double y, double z) {
+ return scaleLocal(x, y, z, this);
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(double, Vector3dc) rotate()} instead.
+ *
+ * @see #rotate(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about (needs to be {@link Vector3d#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotation(double angle, Vector3dc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(double, Vector3fc) rotate()} instead.
+ *
+ * @see #rotate(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotation(double angle, Vector3fc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4f) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotation(AxisAngle4f axisAngle) {
+ return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4d) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotation(AxisAngle4d axisAngle) {
+ return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(double, double, double, double) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the rotation axis
+ * @param y
+ * the y-component of the rotation axis
+ * @param z
+ * the z-component of the rotation axis
+ * @return this
+ */
+ public Matrix3d rotation(double angle, double x, double y, double z) {
+ double sin = Math.sin(angle);
+ double cos = Math.cosFromSin(sin, angle);
+ double C = 1.0 - cos;
+ double xy = x * y, xz = x * z, yz = y * z;
+ m00 = cos + x * x * C;
+ m10 = xy * C - z * sin;
+ m20 = xz * C + y * sin;
+ m01 = xy * C + z * sin;
+ m11 = cos + y * y * C;
+ m21 = yz * C - x * sin;
+ m02 = xz * C - y * sin;
+ m12 = yz * C + x * sin;
+ m22 = cos + z * z * C;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3d rotationX(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = 1.0;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = cos;
+ m12 = sin;
+ m20 = 0.0;
+ m21 = -sin;
+ m22 = cos;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3d rotationY(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = 0.0;
+ m02 = -sin;
+ m10 = 0.0;
+ m11 = 1.0;
+ m12 = 0.0;
+ m20 = sin;
+ m21 = 0.0;
+ m22 = cos;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3d rotationZ(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = sin;
+ m02 = 0.0;
+ m10 = -sin;
+ m11 = cos;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3d rotationXYZ(double angleX, double angleY, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm11 = cosX;
+ double nm12 = sinX;
+ double nm21 = m_sinX;
+ double nm22 = cosX;
+ // rotateY
+ double nm00 = cosY;
+ double nm01 = nm21 * m_sinY;
+ double nm02 = nm22 * m_sinY;
+ m20 = sinY;
+ m21 = nm21 * cosY;
+ m22 = nm22 * cosY;
+ // rotateZ
+ m00 = nm00 * cosZ;
+ m01 = nm01 * cosZ + nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ;
+ m11 = nm01 * m_sinZ + nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix3d rotationZYX(double angleZ, double angleY, double angleX) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = cosZ;
+ double nm01 = sinZ;
+ double nm10 = m_sinZ;
+ double nm11 = cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY;
+ double nm21 = nm01 * sinY;
+ double nm22 = cosY;
+ m00 = nm00 * cosY;
+ m01 = nm01 * cosY;
+ m02 = m_sinY;
+ // rotateX
+ m10 = nm10 * cosX + nm20 * sinX;
+ m11 = nm11 * cosX + nm21 * sinX;
+ m12 = nm22 * sinX;
+ m20 = nm10 * m_sinX + nm20 * cosX;
+ m21 = nm11 * m_sinX + nm21 * cosX;
+ m22 = nm22 * cosX;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3d rotationYXZ(double angleY, double angleX, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm00 = cosY;
+ double nm02 = m_sinY;
+ double nm20 = sinY;
+ double nm22 = cosY;
+ // rotateX
+ double nm10 = nm20 * sinX;
+ double nm11 = cosX;
+ double nm12 = nm22 * sinX;
+ m20 = nm20 * cosX;
+ m21 = m_sinX;
+ m22 = nm22 * cosX;
+ // rotateZ
+ m00 = nm00 * cosZ + nm10 * sinZ;
+ m01 = nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ + nm10 * cosZ;
+ m11 = nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return this;
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniondc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaterniondc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix3d rotation(Quaterniondc quat) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw;
+ double xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz;
+ double yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz;
+ double xw = quat.x() * quat.w(), dxw = xw + xw;
+ m00 = w2 + x2 - z2 - y2;
+ m01 = dxy + dzw;
+ m02 = dxz - dyw;
+ m10 = -dzw + dxy;
+ m11 = y2 - z2 + w2 - x2;
+ m12 = dyz + dxw;
+ m20 = dyw + dxz;
+ m21 = dyz - dxw;
+ m22 = z2 - y2 - x2 + w2;
+ return this;
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaternionfc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaternionfc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3d rotation(Quaternionfc quat) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw;
+ double xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz;
+ double yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz;
+ double xw = quat.x() * quat.w(), dxw = xw + xw;
+ m00 = w2 + x2 - z2 - y2;
+ m01 = dxy + dzw;
+ m02 = dxz - dyw;
+ m10 = -dzw + dxy;
+ m11 = y2 - z2 + w2 - x2;
+ m12 = dyz + dxw;
+ m20 = dyw + dxz;
+ m21 = dyz - dxw;
+ m22 = z2 - y2 - x2 + w2;
+ return this;
+ }
+
+ public Vector3d transform(Vector3d v) {
+ return v.mul(this);
+ }
+
+ public Vector3d transform(Vector3dc v, Vector3d dest) {
+ v.mul(this, dest);
+ return dest;
+ }
+
+ public Vector3f transform(Vector3f v) {
+ return v.mul(this);
+ }
+
+ public Vector3f transform(Vector3fc v, Vector3f dest) {
+ return v.mul(this, dest);
+ }
+
+ public Vector3d transform(double x, double y, double z, Vector3d dest) {
+ return dest.set(Math.fma(m00, x, Math.fma(m10, y, m20 * z)),
+ Math.fma(m01, x, Math.fma(m11, y, m21 * z)),
+ Math.fma(m02, x, Math.fma(m12, y, m22 * z)));
+ }
+
+ public Vector3d transformTranspose(Vector3d v) {
+ return v.mulTranspose(this);
+ }
+
+ public Vector3d transformTranspose(Vector3dc v, Vector3d dest) {
+ return v.mulTranspose(this, dest);
+ }
+
+ public Vector3d transformTranspose(double x, double y, double z, Vector3d dest) {
+ return dest.set(Math.fma(m00, x, Math.fma(m01, y, m02 * z)),
+ Math.fma(m10, x, Math.fma(m11, y, m12 * z)),
+ Math.fma(m20, x, Math.fma(m21, y, m22 * z)));
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(m00);
+ out.writeDouble(m01);
+ out.writeDouble(m02);
+ out.writeDouble(m10);
+ out.writeDouble(m11);
+ out.writeDouble(m12);
+ out.writeDouble(m20);
+ out.writeDouble(m21);
+ out.writeDouble(m22);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readDouble();
+ m01 = in.readDouble();
+ m02 = in.readDouble();
+ m10 = in.readDouble();
+ m11 = in.readDouble();
+ m12 = in.readDouble();
+ m20 = in.readDouble();
+ m21 = in.readDouble();
+ m22 = in.readDouble();
+ }
+
+ public Matrix3d rotateX(double ang, Matrix3d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm11 = cos;
+ double rm21 = -sin;
+ double rm12 = sin;
+ double rm22 = cos;
+
+ // add temporaries for dependent values
+ double nm10 = m10 * rm11 + m20 * rm12;
+ double nm11 = m11 * rm11 + m21 * rm12;
+ double nm12 = m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m10 * rm21 + m20 * rm22;
+ dest.m21 = m11 * rm21 + m21 * rm22;
+ dest.m22 = m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3d rotateX(double ang) {
+ return rotateX(ang, this);
+ }
+
+ public Matrix3d rotateY(double ang, Matrix3d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm00 = cos;
+ double rm20 = sin;
+ double rm02 = -sin;
+ double rm22 = cos;
+
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m20 * rm02;
+ double nm01 = m01 * rm00 + m21 * rm02;
+ double nm02 = m02 * rm00 + m22 * rm02;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3d rotateY(double ang) {
+ return rotateY(ang, this);
+ }
+
+ public Matrix3d rotateZ(double ang, Matrix3d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm00 = cos;
+ double rm10 = -sin;
+ double rm01 = sin;
+ double rm11 = cos;
+
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m10 * rm01;
+ double nm01 = m01 * rm00 + m11 * rm01;
+ double nm02 = m02 * rm00 + m12 * rm01;
+ // set non-dependent values directly
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m12 = m02 * rm10 + m12 * rm11;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3d rotateZ(double ang) {
+ return rotateZ(ang, this);
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3d rotateXYZ(double angleX, double angleY, double angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix3d rotateXYZ(double angleX, double angleY, double angleZ, Matrix3d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm10 = m10 * cosX + m20 * sinX;
+ double nm11 = m11 * cosX + m21 * sinX;
+ double nm12 = m12 * cosX + m22 * sinX;
+ double nm20 = m10 * m_sinX + m20 * cosX;
+ double nm21 = m11 * m_sinX + m21 * cosX;
+ double nm22 = m12 * m_sinX + m22 * cosX;
+ // rotateY
+ double nm00 = m00 * cosY + nm20 * m_sinY;
+ double nm01 = m01 * cosY + nm21 * m_sinY;
+ double nm02 = m02 * cosY + nm22 * m_sinY;
+ dest.m20 = m00 * sinY + nm20 * cosY;
+ dest.m21 = m01 * sinY + nm21 * cosY;
+ dest.m22 = m02 * sinY + nm22 * cosY;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix3d rotateZYX(double angleZ, double angleY, double angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix3d rotateZYX(double angleZ, double angleY, double angleX, Matrix3d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = m00 * cosZ + m10 * sinZ;
+ double nm01 = m01 * cosZ + m11 * sinZ;
+ double nm02 = m02 * cosZ + m12 * sinZ;
+ double nm10 = m00 * m_sinZ + m10 * cosZ;
+ double nm11 = m01 * m_sinZ + m11 * cosZ;
+ double nm12 = m02 * m_sinZ + m12 * cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY + m20 * cosY;
+ double nm21 = nm01 * sinY + m21 * cosY;
+ double nm22 = nm02 * sinY + m22 * cosY;
+ dest.m00 = nm00 * cosY + m20 * m_sinY;
+ dest.m01 = nm01 * cosY + m21 * m_sinY;
+ dest.m02 = nm02 * cosY + m22 * m_sinY;
+ // rotateX
+ dest.m10 = nm10 * cosX + nm20 * sinX;
+ dest.m11 = nm11 * cosX + nm21 * sinX;
+ dest.m12 = nm12 * cosX + nm22 * sinX;
+ dest.m20 = nm10 * m_sinX + nm20 * cosX;
+ dest.m21 = nm11 * m_sinX + nm21 * cosX;
+ dest.m22 = nm12 * m_sinX + nm22 * cosX;
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.y
radians about the Y axis, followed by a rotation of angles.x
radians about the X axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix3d rotateYXZ(Vector3d angles) {
+ return rotateYXZ(angles.y, angles.x, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3d rotateYXZ(double angleY, double angleX, double angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix3d rotateYXZ(double angleY, double angleX, double angleZ, Matrix3d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm20 = m00 * sinY + m20 * cosY;
+ double nm21 = m01 * sinY + m21 * cosY;
+ double nm22 = m02 * sinY + m22 * cosY;
+ double nm00 = m00 * cosY + m20 * m_sinY;
+ double nm01 = m01 * cosY + m21 * m_sinY;
+ double nm02 = m02 * cosY + m22 * m_sinY;
+ // rotateX
+ double nm10 = m10 * cosX + nm20 * sinX;
+ double nm11 = m11 * cosX + nm21 * sinX;
+ double nm12 = m12 * cosX + nm22 * sinX;
+ dest.m20 = m10 * m_sinX + nm20 * cosX;
+ dest.m21 = m11 * m_sinX + nm21 * cosX;
+ dest.m22 = m12 * m_sinX + nm22 * cosX;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix3d rotate(double ang, double x, double y, double z) {
+ return rotate(ang, x, y, z, this);
+ }
+
+ public Matrix3d rotate(double ang, double x, double y, double z, Matrix3d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+
+ // rotation matrix elements:
+ // m30, m31, m32, m03, m13, m23 = 0
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double rm00 = xx * C + c;
+ double rm01 = xy * C + z * s;
+ double rm02 = xz * C - y * s;
+ double rm10 = xy * C - z * s;
+ double rm11 = yy * C + c;
+ double rm12 = yz * C + x * s;
+ double rm20 = xz * C + y * s;
+ double rm21 = yz * C - x * s;
+ double rm22 = zz * C + c;
+
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateLocal(double ang, double x, double y, double z, Matrix3d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double lm00 = xx * C + c;
+ double lm01 = xy * C + z * s;
+ double lm02 = xz * C - y * s;
+ double lm10 = xy * C - z * s;
+ double lm11 = yy * C + c;
+ double lm12 = yz * C + x * s;
+ double lm20 = xz * C + y * s;
+ double lm21 = yz * C - x * s;
+ double lm22 = zz * C + c;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix3d rotateLocal(double ang, double x, double y, double z) {
+ return rotateLocal(ang, x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(double) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateLocalX(double ang, Matrix3d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm01 = cos * m01 - sin * m02;
+ double nm02 = sin * m01 + cos * m02;
+ double nm11 = cos * m11 - sin * m12;
+ double nm12 = sin * m11 + cos * m12;
+ double nm21 = cos * m21 - sin * m22;
+ double nm22 = sin * m21 + cos * m22;
+ dest.m00 = m00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = m20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(double) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix3d rotateLocalX(double ang) {
+ return rotateLocalX(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateLocalY(double ang, Matrix3d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm00 = cos * m00 + sin * m02;
+ double nm02 = -sin * m00 + cos * m02;
+ double nm10 = cos * m10 + sin * m12;
+ double nm12 = -sin * m10 + cos * m12;
+ double nm20 = cos * m20 + sin * m22;
+ double nm22 = -sin * m20 + cos * m22;
+ dest.m00 = nm00;
+ dest.m01 = m01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = m11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = m21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @return this
+ */
+ public Matrix3d rotateLocalY(double ang) {
+ return rotateLocalY(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(double) rotationZ()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationZ(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateLocalZ(double ang, Matrix3d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm00 = cos * m00 - sin * m01;
+ double nm01 = sin * m00 + cos * m01;
+ double nm10 = cos * m10 - sin * m11;
+ double nm11 = sin * m10 + cos * m11;
+ double nm20 = cos * m20 - sin * m21;
+ double nm21 = sin * m20 + cos * m21;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = m02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = m12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = m22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @return this
+ */
+ public Matrix3d rotateLocalZ(double ang) {
+ return rotateLocalZ(ang, this);
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateLocal(Quaterniondc quat, Matrix3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = dxy + dzw;
+ double lm02 = dxz - dyw;
+ double lm10 = dxy - dzw;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = dyz + dxw;
+ double lm20 = dyw + dxz;
+ double lm21 = dyz - dxw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix3d rotateLocal(Quaterniondc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateLocal(Quaternionfc quat, Matrix3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = dxy + dzw;
+ double lm02 = dxz - dyw;
+ double lm10 = dxy - dzw;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = dyz + dxw;
+ double lm20 = dyw + dxz;
+ double lm21 = dyz - dxw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3d rotateLocal(Quaternionfc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix3d rotate(Quaterniondc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotate(Quaterniondc quat, Matrix3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = dxy - dzw;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3d rotate(Quaternionfc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotate(Quaternionfc quat, Matrix3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = dxy - dzw;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotate(AxisAngle4f axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotate(AxisAngle4f axisAngle, Matrix3d dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4d)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotate(AxisAngle4d axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4d)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotate(AxisAngle4d axisAngle, Matrix3d dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3dc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotate(double angle, Vector3dc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis and angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3dc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotate(double angle, Vector3dc axis, Matrix3d dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3d rotate(double angle, Vector3fc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis and angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotate(double angle, Vector3fc axis, Matrix3d dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ public Vector3d getRow(int row, Vector3d dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ return dest.set(m00, m10, m20);
+ case 1:
+ return dest.set(m01, m11, m21);
+ case 2:
+ return dest.set(m02, m12, m22);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ public Matrix3d setRow(int row, Vector3dc src) throws IndexOutOfBoundsException {
+ return setRow(row, src.x(), src.y(), src.z());
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the column index in [0..2]
+ * @param x
+ * the first element in the row
+ * @param y
+ * the second element in the row
+ * @param z
+ * the third element in the row
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ public Matrix3d setRow(int row, double x, double y, double z) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ this.m00 = x;
+ this.m10 = y;
+ this.m20 = z;
+ break;
+ case 1:
+ this.m01 = x;
+ this.m11 = y;
+ this.m21 = z;
+ break;
+ case 2:
+ this.m02 = x;
+ this.m12 = y;
+ this.m22 = z;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public Vector3d getColumn(int column, Vector3d dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ return dest.set(m00, m01, m02);
+ case 1:
+ return dest.set(m10, m11, m12);
+ case 2:
+ return dest.set(m20, m21, m22);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ public Matrix3d setColumn(int column, Vector3dc src) throws IndexOutOfBoundsException {
+ return setColumn(column, src.x(), src.y(), src.z());
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param x
+ * the first element in the column
+ * @param y
+ * the second element in the column
+ * @param z
+ * the third element in the column
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ public Matrix3d setColumn(int column, double x, double y, double z) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ this.m00 = x;
+ this.m01 = y;
+ this.m02 = z;
+ break;
+ case 1:
+ this.m10 = x;
+ this.m11 = y;
+ this.m12 = z;
+ break;
+ case 2:
+ this.m20 = x;
+ this.m21 = y;
+ this.m22 = z;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public double get(int column, int row) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given column and row to the specified value.
+ *
+ * @param column
+ * the colum index in [0..2]
+ * @param row
+ * the row index in [0..2]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix3d set(int column, int row, double value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ public double getRowColumn(int row, int column) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given row and column to the specified value.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param column
+ * the colum index in [0..2]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix3d setRowColumn(int row, int column, double value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ /**
+ * Set this
matrix to its own normal matrix.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix3dc)} to set a given Matrix3f to this matrix.
+ *
+ * @see #set(Matrix3dc)
+ *
+ * @return this
+ */
+ public Matrix3d normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix3dc)} to set a given Matrix3d to this matrix.
+ *
+ * @see #set(Matrix3dc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d normal(Matrix3d dest) {
+ double m00m11 = m00 * m11;
+ double m01m10 = m01 * m10;
+ double m02m10 = m02 * m10;
+ double m00m12 = m00 * m12;
+ double m01m12 = m01 * m12;
+ double m02m11 = m02 * m11;
+ double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ double s = 1.0 / det;
+ /* Invert and transpose in one go */
+ double nm00 = (m11 * m22 - m21 * m12) * s;
+ double nm01 = (m20 * m12 - m10 * m22) * s;
+ double nm02 = (m10 * m21 - m20 * m11) * s;
+ double nm10 = (m21 * m02 - m01 * m22) * s;
+ double nm11 = (m00 * m22 - m20 * m02) * s;
+ double nm12 = (m20 * m01 - m00 * m21) * s;
+ double nm20 = (m01m12 - m02m11) * s;
+ double nm21 = (m02m10 - m00m12) * s;
+ double nm22 = (m00m11 - m01m10) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Compute the cofactor matrix of this
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal()} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @return this
+ */
+ public Matrix3d cofactor() {
+ return cofactor(this);
+ }
+
+ /**
+ * Compute the cofactor matrix of this
and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d cofactor(Matrix3d dest) {
+ double nm00 = m11 * m22 - m21 * m12;
+ double nm01 = m20 * m12 - m10 * m22;
+ double nm02 = m10 * m21 - m20 * m11;
+ double nm10 = m21 * m02 - m01 * m22;
+ double nm11 = m00 * m22 - m20 * m02;
+ double nm12 = m20 * m01 - m00 * m21;
+ double nm20 = m01 * m12 - m11 * m02;
+ double nm21 = m02 * m10 - m12 * m00;
+ double nm22 = m00 * m11 - m10 * m01;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3dc, Vector3dc) setLookAlong()}.
+ *
+ * @see #lookAlong(double, double, double, double, double, double)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix3d lookAlong(Vector3dc dir, Vector3dc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3dc, Vector3dc) setLookAlong()}.
+ *
+ * @see #lookAlong(double, double, double, double, double, double)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d lookAlong(Vector3dc dir, Vector3dc up, Matrix3d dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
+ *
+ * @see #setLookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d lookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ, Matrix3d dest) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+
+ // perform optimized matrix multiplication
+ // introduce temporaries for dependent results
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
+ *
+ * @see #setLookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3d lookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(Vector3dc, Vector3dc)}.
+ *
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ * @see #lookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix3d setLookAlong(Vector3dc dir, Vector3dc up) {
+ return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()}
+ *
+ * @see #setLookAlong(double, double, double, double, double, double)
+ * @see #lookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3d setLookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+
+ return this;
+ }
+
+ public Vector3d getScale(Vector3d dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest;
+ }
+
+ public Vector3d positiveZ(Vector3d dir) {
+ dir.x = m10 * m21 - m11 * m20;
+ dir.y = m20 * m01 - m21 * m00;
+ dir.z = m00 * m11 - m01 * m10;
+ return dir.normalize(dir);
+ }
+
+ public Vector3d normalizedPositiveZ(Vector3d dir) {
+ dir.x = m02;
+ dir.y = m12;
+ dir.z = m22;
+ return dir;
+ }
+
+ public Vector3d positiveX(Vector3d dir) {
+ dir.x = m11 * m22 - m12 * m21;
+ dir.y = m02 * m21 - m01 * m22;
+ dir.z = m01 * m12 - m02 * m11;
+ return dir.normalize(dir);
+ }
+
+ public Vector3d normalizedPositiveX(Vector3d dir) {
+ dir.x = m00;
+ dir.y = m10;
+ dir.z = m20;
+ return dir;
+ }
+
+ public Vector3d positiveY(Vector3d dir) {
+ dir.x = m12 * m20 - m10 * m22;
+ dir.y = m00 * m22 - m02 * m20;
+ dir.z = m02 * m10 - m00 * m12;
+ return dir.normalize(dir);
+ }
+
+ public Vector3d normalizedPositiveY(Vector3d dir) {
+ dir.x = m01;
+ dir.y = m11;
+ dir.z = m21;
+ return dir;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(m00);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m01);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m02);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m10);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m11);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m12);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m20);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m21);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m22);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Matrix3d other = (Matrix3d) obj;
+ if (Double.doubleToLongBits(m00) != Double.doubleToLongBits(other.m00))
+ return false;
+ if (Double.doubleToLongBits(m01) != Double.doubleToLongBits(other.m01))
+ return false;
+ if (Double.doubleToLongBits(m02) != Double.doubleToLongBits(other.m02))
+ return false;
+ if (Double.doubleToLongBits(m10) != Double.doubleToLongBits(other.m10))
+ return false;
+ if (Double.doubleToLongBits(m11) != Double.doubleToLongBits(other.m11))
+ return false;
+ if (Double.doubleToLongBits(m12) != Double.doubleToLongBits(other.m12))
+ return false;
+ if (Double.doubleToLongBits(m20) != Double.doubleToLongBits(other.m20))
+ return false;
+ if (Double.doubleToLongBits(m21) != Double.doubleToLongBits(other.m21))
+ return false;
+ if (Double.doubleToLongBits(m22) != Double.doubleToLongBits(other.m22))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix3dc m, double delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix3d))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m02, m.m02(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m12, m.m12(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ if (!Runtime.equals(m22, m.m22(), delta))
+ return false;
+ return true;
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix3d swap(Matrix3d other) {
+ double tmp;
+ tmp = m00; m00 = other.m00; other.m00 = tmp;
+ tmp = m01; m01 = other.m01; other.m01 = tmp;
+ tmp = m02; m02 = other.m02; other.m02 = tmp;
+ tmp = m10; m10 = other.m10; other.m10 = tmp;
+ tmp = m11; m11 = other.m11; other.m11 = tmp;
+ tmp = m12; m12 = other.m12; other.m12 = tmp;
+ tmp = m20; m20 = other.m20; other.m20 = tmp;
+ tmp = m21; m21 = other.m21; other.m21 = tmp;
+ tmp = m22; m22 = other.m22; other.m22 = tmp;
+ return this;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix3d add(Matrix3dc other) {
+ return add(other, this);
+ }
+
+ public Matrix3d add(Matrix3dc other, Matrix3d dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m02 = m02 + other.m02();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ dest.m12 = m12 + other.m12();
+ dest.m20 = m20 + other.m20();
+ dest.m21 = m21 + other.m21();
+ dest.m22 = m22 + other.m22();
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix3d sub(Matrix3dc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix3d sub(Matrix3dc subtrahend, Matrix3d dest) {
+ dest.m00 = m00 - subtrahend.m00();
+ dest.m01 = m01 - subtrahend.m01();
+ dest.m02 = m02 - subtrahend.m02();
+ dest.m10 = m10 - subtrahend.m10();
+ dest.m11 = m11 - subtrahend.m11();
+ dest.m12 = m12 - subtrahend.m12();
+ dest.m20 = m20 - subtrahend.m20();
+ dest.m21 = m21 - subtrahend.m21();
+ dest.m22 = m22 - subtrahend.m22();
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix3d mulComponentWise(Matrix3dc other) {
+ return mulComponentWise(other, this);
+ }
+
+ public Matrix3d mulComponentWise(Matrix3dc other, Matrix3d dest) {
+ dest.m00 = m00 * other.m00();
+ dest.m01 = m01 * other.m01();
+ dest.m02 = m02 * other.m02();
+ dest.m10 = m10 * other.m10();
+ dest.m11 = m11 * other.m11();
+ dest.m12 = m12 * other.m12();
+ dest.m20 = m20 * other.m20();
+ dest.m21 = m21 * other.m21();
+ dest.m22 = m22 * other.m22();
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a skew-symmetric matrix using the following layout:
+ *
+ * 0, a, -b
+ * -a, 0, c
+ * b, -c, 0
+ *
+ *
+ * Reference: https://en.wikipedia.org
+ *
+ * @param a
+ * the value used for the matrix elements m01 and m10
+ * @param b
+ * the value used for the matrix elements m02 and m20
+ * @param c
+ * the value used for the matrix elements m12 and m21
+ * @return this
+ */
+ public Matrix3d setSkewSymmetric(double a, double b, double c) {
+ m00 = m11 = m22 = 0;
+ m01 = -a;
+ m02 = b;
+ m10 = a;
+ m12 = -c;
+ m20 = -b;
+ m21 = c;
+ return this;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix3d lerp(Matrix3dc other, double t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix3d lerp(Matrix3dc other, double t, Matrix3d dest) {
+ dest.m00 = Math.fma(other.m00() - m00, t, m00);
+ dest.m01 = Math.fma(other.m01() - m01, t, m01);
+ dest.m02 = Math.fma(other.m02() - m02, t, m02);
+ dest.m10 = Math.fma(other.m10() - m10, t, m10);
+ dest.m11 = Math.fma(other.m11() - m11, t, m11);
+ dest.m12 = Math.fma(other.m12() - m12, t, m12);
+ dest.m20 = Math.fma(other.m20() - m20, t, m20);
+ dest.m21 = Math.fma(other.m21() - m21, t, m21);
+ dest.m22 = Math.fma(other.m22() - m22, t, m22);
+ return dest;
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3dc, Vector3dc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3d().lookAlong(new Vector3d(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(double, double, double, double, double, double, Matrix3d)
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ *
+ * @param direction
+ * the direction to rotate towards
+ * @param up
+ * the model's up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateTowards(Vector3dc direction, Vector3dc up, Matrix3d dest) {
+ return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3dc, Vector3dc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3d().lookAlong(new Vector3d(dir).negate(), up).invert())
+ *
+ * @see #rotateTowards(double, double, double, double, double, double)
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ *
+ * @param direction
+ * the direction to orient towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix3d rotateTowards(Vector3dc direction, Vector3dc up) {
+ return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3d().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert())
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3d().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix3d dest) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ double rm00 = leftX;
+ double rm01 = leftY;
+ double rm02 = leftZ;
+ double rm10 = upnX;
+ double rm11 = upnY;
+ double rm12 = upnZ;
+ double rm20 = ndirX;
+ double rm21 = ndirY;
+ double rm22 = ndirZ;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with center - eye
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAlong(new Vector3d(dir).negate(), up).invert()
+ *
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ * @see #rotateTowards(double, double, double, double, double, double)
+ *
+ * @param dir
+ * the direction to orient the local -z axis towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix3d rotationTowards(Vector3dc dir, Vector3dc up) {
+ return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with center - eye
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert()
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ return this;
+ }
+
+ public Vector3d getEulerAnglesZYX(Vector3d dest) {
+ dest.x = Math.atan2(m12, m22);
+ dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02));
+ dest.z = Math.atan2(m01, m00);
+ return dest;
+ }
+
+ public Vector3d getEulerAnglesXYZ(Vector3d dest) {
+ dest.x = Math.atan2(-m21, m22);
+ dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20));
+ dest.z = Math.atan2(-m10, m00);
+ return dest;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a
+ * 0 1 b
+ * 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @return this
+ */
+ public Matrix3d obliqueZ(double a, double b) {
+ this.m20 = m00 * a + m10 * b + m20;
+ this.m21 = m01 * a + m11 * b + m21;
+ this.m22 = m02 * a + m12 * b + m22;
+ return this;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a
+ * 0 1 b
+ * 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d obliqueZ(double a, double b, Matrix3d dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m00 * a + m10 * b + m20;
+ dest.m21 = m01 * a + m11 * b + m21;
+ dest.m22 = m02 * a + m12 * b + m22;
+ return dest;
+ }
+
+ public Matrix3d reflect(double nx, double ny, double nz, Matrix3d dest) {
+ double da = nx + nx, db = ny + ny, dc = nz + nz;
+ double rm00 = 1.0 - da * nx;
+ double rm01 = -da * ny;
+ double rm02 = -da * nz;
+ double rm10 = -db * nx;
+ double rm11 = 1.0 - db * ny;
+ double rm12 = -db * nz;
+ double rm20 = -dc * nx;
+ double rm21 = -dc * ny;
+ double rm22 = 1.0 - dc * nz;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ return dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @return this
+ */
+ public Matrix3d reflect(double nx, double ny, double nz) {
+ return reflect(nx, ny, nz, this);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @return this
+ */
+ public Matrix3d reflect(Vector3dc normal) {
+ return reflect(normal.x(), normal.y(), normal.z());
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @return this
+ */
+ public Matrix3d reflect(Quaterniondc orientation) {
+ return reflect(orientation, this);
+ }
+
+ public Matrix3d reflect(Quaterniondc orientation, Matrix3d dest) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ double normalX = (double) (orientation.x() * num3 + orientation.w() * num2);
+ double normalY = (double) (orientation.y() * num3 - orientation.w() * num1);
+ double normalZ = (double) (1.0 - (orientation.x() * num1 + orientation.y() * num2));
+ return reflect(normalX, normalY, normalZ, dest);
+ }
+
+ public Matrix3d reflect(Vector3dc normal, Matrix3d dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), dest);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @return this
+ */
+ public Matrix3d reflection(double nx, double ny, double nz) {
+ double da = nx + nx, db = ny + ny, dc = nz + nz;
+ this._m00(1.0 - da * nx);
+ this._m01(-da * ny);
+ this._m02(-da * nz);
+ this._m10(-db * nx);
+ this._m11(1.0 - db * ny);
+ this._m12(-db * nz);
+ this._m20(-dc * nx);
+ this._m21(-dc * ny);
+ this._m22(1.0 - dc * nz);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * @param normal
+ * the plane normal
+ * @return this
+ */
+ public Matrix3d reflection(Vector3dc normal) {
+ return reflection(normal.x(), normal.y(), normal.z());
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects through a plane
+ * specified via the plane orientation.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * @param orientation
+ * the plane orientation
+ * @return this
+ */
+ public Matrix3d reflection(Quaterniondc orientation) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ double normalX = orientation.x() * num3 + orientation.w() * num2;
+ double normalY = orientation.y() * num3 - orientation.w() * num1;
+ double normalZ = 1.0 - (orientation.x() * num1 + orientation.y() * num2);
+ return reflection(normalX, normalY, normalZ);
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
+ Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
+ Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22);
+ }
+
+ public double quadraticFormProduct(double x, double y, double z) {
+ double Axx = m00 * x + m10 * y + m20 * z;
+ double Axy = m01 * x + m11 * y + m21 * z;
+ double Axz = m02 * x + m12 * y + m22 * z;
+ return x * Axx + y * Axy + z * Axz;
+ }
+
+ public double quadraticFormProduct(Vector3dc v) {
+ return quadraticFormProduct(v.x(), v.y(), v.z());
+ }
+
+ public double quadraticFormProduct(Vector3fc v) {
+ return quadraticFormProduct(v.x(), v.y(), v.z());
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapXZY() {
+ return mapXZY(this);
+ }
+ public Matrix3d mapXZY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapXZnY() {
+ return mapXZnY(this);
+ }
+ public Matrix3d mapXZnY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapXnYnZ() {
+ return mapXnYnZ(this);
+ }
+ public Matrix3d mapXnYnZ(Matrix3d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapXnZY() {
+ return mapXnZY(this);
+ }
+ public Matrix3d mapXnZY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapXnZnY() {
+ return mapXnZnY(this);
+ }
+ public Matrix3d mapXnZnY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYXZ() {
+ return mapYXZ(this);
+ }
+ public Matrix3d mapYXZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYXnZ() {
+ return mapYXnZ(this);
+ }
+ public Matrix3d mapYXnZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYZX() {
+ return mapYZX(this);
+ }
+ public Matrix3d mapYZX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYZnX() {
+ return mapYZnX(this);
+ }
+ public Matrix3d mapYZnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYnXZ() {
+ return mapYnXZ(this);
+ }
+ public Matrix3d mapYnXZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYnXnZ() {
+ return mapYnXnZ(this);
+ }
+ public Matrix3d mapYnXnZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYnZX() {
+ return mapYnZX(this);
+ }
+ public Matrix3d mapYnZX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapYnZnX() {
+ return mapYnZnX(this);
+ }
+ public Matrix3d mapYnZnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZXY() {
+ return mapZXY(this);
+ }
+ public Matrix3d mapZXY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZXnY() {
+ return mapZXnY(this);
+ }
+ public Matrix3d mapZXnY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZYX() {
+ return mapZYX(this);
+ }
+ public Matrix3d mapZYX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZYnX() {
+ return mapZYnX(this);
+ }
+ public Matrix3d mapZYnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZnXY() {
+ return mapZnXY(this);
+ }
+ public Matrix3d mapZnXY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZnXnY() {
+ return mapZnXnY(this);
+ }
+ public Matrix3d mapZnXnY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZnYX() {
+ return mapZnYX(this);
+ }
+ public Matrix3d mapZnYX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapZnYnX() {
+ return mapZnYnX(this);
+ }
+ public Matrix3d mapZnYnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXYnZ() {
+ return mapnXYnZ(this);
+ }
+ public Matrix3d mapnXYnZ(Matrix3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXZY() {
+ return mapnXZY(this);
+ }
+ public Matrix3d mapnXZY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXZnY() {
+ return mapnXZnY(this);
+ }
+ public Matrix3d mapnXZnY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXnYZ() {
+ return mapnXnYZ(this);
+ }
+ public Matrix3d mapnXnYZ(Matrix3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXnYnZ() {
+ return mapnXnYnZ(this);
+ }
+ public Matrix3d mapnXnYnZ(Matrix3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXnZY() {
+ return mapnXnZY(this);
+ }
+ public Matrix3d mapnXnZY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnXnZnY() {
+ return mapnXnZnY(this);
+ }
+ public Matrix3d mapnXnZnY(Matrix3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYXZ() {
+ return mapnYXZ(this);
+ }
+ public Matrix3d mapnYXZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYXnZ() {
+ return mapnYXnZ(this);
+ }
+ public Matrix3d mapnYXnZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYZX() {
+ return mapnYZX(this);
+ }
+ public Matrix3d mapnYZX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYZnX() {
+ return mapnYZnX(this);
+ }
+ public Matrix3d mapnYZnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYnXZ() {
+ return mapnYnXZ(this);
+ }
+ public Matrix3d mapnYnXZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYnXnZ() {
+ return mapnYnXnZ(this);
+ }
+ public Matrix3d mapnYnXnZ(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYnZX() {
+ return mapnYnZX(this);
+ }
+ public Matrix3d mapnYnZX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnYnZnX() {
+ return mapnYnZnX(this);
+ }
+ public Matrix3d mapnYnZnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZXY() {
+ return mapnZXY(this);
+ }
+ public Matrix3d mapnZXY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZXnY() {
+ return mapnZXnY(this);
+ }
+ public Matrix3d mapnZXnY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZYX() {
+ return mapnZYX(this);
+ }
+ public Matrix3d mapnZYX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZYnX() {
+ return mapnZYnX(this);
+ }
+ public Matrix3d mapnZYnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZnXY() {
+ return mapnZnXY(this);
+ }
+ public Matrix3d mapnZnXY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZnXnY() {
+ return mapnZnXnY(this);
+ }
+ public Matrix3d mapnZnXnY(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZnYX() {
+ return mapnZnYX(this);
+ }
+ public Matrix3d mapnZnYX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3d mapnZnYnX() {
+ return mapnZnYnX(this);
+ }
+ public Matrix3d mapnZnYnX(Matrix3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d negateX() {
+ return _m00(-m00)._m01(-m01)._m02(-m02);
+ }
+ public Matrix3d negateX(Matrix3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(m20)._m21(m21)._m22(m22);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d negateY() {
+ return _m10(-m10)._m11(-m11)._m12(-m12);
+ }
+ public Matrix3d negateY(Matrix3d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3d negateZ() {
+ return _m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ public Matrix3d negateZ(Matrix3d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3dStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3dStack.java
new file mode 100644
index 000000000..a522ec31b
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3dStack.java
@@ -0,0 +1,186 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2018-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix3d} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix3dStack} class inherits from {@link Matrix3d}, so the current/top matrix is always the
+ * {@link Matrix3dStack}/{@link Matrix3d} itself. This affects all operations in {@link Matrix3d} that take another
+ * {@link Matrix3d} as parameter. If a {@link Matrix3dStack} is used as argument to those methods, the effective
+ * argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix3dStack extends Matrix3d {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix3dStack(int) constructor}.
+ */
+ private Matrix3d[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix3dStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix3dStack} simply only consists of this
+ * {@link Matrix3d}
+ */
+ public Matrix3dStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix3d[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix3d();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix3dStack} instance.
+ */
+ public Matrix3dStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix3dStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix3dStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix3dStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix3d and Matrix3dStack:
+ *
+ * - Matrix3d.equals(Matrix3dStack) is true iff all the 9 matrix elements are equal
+ * - Matrix3dStack.equals(Matrix3d) is true iff all the 9 matrix elements are equal
+ * - Matrix3dStack.equals(Matrix3dStack) is true iff all 9 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix3dStack) {
+ Matrix3dStack other = (Matrix3dStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix3dStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix3d m = new Matrix3d();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix3dStack cloned = (Matrix3dStack) super.clone();
+ Matrix3d[] clonedMats = new Matrix3d[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix3d) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3dc.java
new file mode 100644
index 000000000..18a330ecd
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3dc.java
@@ -0,0 +1,2310 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 3x3 matrix of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix3dc {
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m01();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m02();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m11();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m12();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m21();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m22();
+
+ /**
+ * Multiply this matrix by the supplied matrix and store the result in dest
.
+ * This matrix will be the left one.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mul(Matrix3dc right, Matrix3d dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix3d mulLocal(Matrix3dc left, Matrix3d dest);
+
+ /**
+ * Multiply this matrix by the supplied matrix and store the result in dest
.
+ * This matrix will be the left one.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mul(Matrix3fc right, Matrix3d dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ double determinant();
+
+ /**
+ * Invert this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d invert(Matrix3d dest);
+
+ /**
+ * Transpose this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d transpose(Matrix3d dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3d get(Matrix3d dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link AxisAngle4f}.
+ *
+ * @see AxisAngle4f#set(Matrix3dc)
+ *
+ * @param dest
+ * the destination {@link AxisAngle4f}
+ * @return the passed in destination
+ */
+ AxisAngle4f getRotation(AxisAngle4f dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the three column vectors of this matrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaternionf#setFromUnnormalized(Matrix3dc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getUnnormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the three column vectors of this matrix are normalized.
+ *
+ * @see Quaternionf#setFromNormalized(Matrix3dc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getNormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the three column vectors of this matrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaterniond#setFromUnnormalized(Matrix3dc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getUnnormalizedRotation(Quaterniond dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the three column vectors of this matrix are normalized.
+ *
+ * @see Quaterniond#setFromNormalized(Matrix3dc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getNormalizedRotation(Quaterniond dest);
+
+ /**
+ * Store this matrix into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position} using column-major order.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer} at which
+ * the matrix is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index using column-major order.
+ *
+ * This method will not increment the position of the given {@link DoubleBuffer}.
+ *
+ * @param index
+ * the absolute position into the {@link DoubleBuffer}
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getFloats(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getFloats(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the elements of this matrix as float values in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getFloats(ByteBuffer buffer);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the elements of this matrix as float values in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getFloats(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix3dc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get(double[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(double[], int)}.
+ *
+ * @see #get(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get(double[] arr);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied float array at the given offset.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied float array.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d scale(Vector3dc xyz, Matrix3d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d scale(double x, double y, double z, Matrix3d dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, double, Matrix3d)
+ *
+ * @param xyz
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d scale(double xyz, Matrix3d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d scaleLocal(double x, double y, double z, Matrix3d dest);
+
+ /**
+ * Transform the given vector by this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector3d transform(Vector3d v);
+
+ /**
+ * Transform the given vector by this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform the given vector by this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector3f transform(Vector3f v);
+
+ /**
+ * Transform the given vector by this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform the vector (x, y, z)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector by the transpose of this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector3d transformTranspose(Vector3d v);
+
+ /**
+ * Transform the given vector by the transpose of this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformTranspose(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform the vector (x, y, z)
by the transpose of this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformTranspose(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateX(double ang, Matrix3d dest);
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateY(double ang, Matrix3d dest);
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateZ(double ang, Matrix3d dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateXYZ(double angleX, double angleY, double angleZ, Matrix3d dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateZYX(double angleZ, double angleY, double angleX, Matrix3d dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateYXZ(double angleY, double angleX, double angleZ, Matrix3d dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components, and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(double ang, double x, double y, double z, Matrix3d dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateLocal(double ang, double x, double y, double z, Matrix3d dest);
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateLocalX(double ang, Matrix3d dest);
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateLocalY(double ang, Matrix3d dest);
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateLocalZ(double ang, Matrix3d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateLocal(Quaterniondc quat, Matrix3d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateLocal(Quaternionfc quat, Matrix3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(Quaterniondc quat, Matrix3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(Quaternionfc quat, Matrix3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix3d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(AxisAngle4f axisAngle, Matrix3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix3d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(AxisAngle4d axisAngle, Matrix3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis and angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix3d)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(double angle, Vector3dc axis, Matrix3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis and angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix3d)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotate(double angle, Vector3fc axis, Matrix3d dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ Vector3d getRow(int row, Vector3d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ Vector3d getColumn(int column, Vector3d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the matrix element value at the given column and row.
+ *
+ * @param column
+ * the colum index in [0..2]
+ * @param row
+ * the row index in [0..2]
+ * @return the element value
+ */
+ double get(int column, int row);
+
+ /**
+ * Get the matrix element value at the given row and column.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param column
+ * the colum index in [0..2]
+ * @return the element value
+ */
+ double getRowColumn(int row, int column);
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d normal(Matrix3d dest);
+
+ /**
+ * Compute the cofactor matrix of this
and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d cofactor(Matrix3d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * @see #lookAlong(double, double, double, double, double, double, Matrix3d)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d lookAlong(Vector3dc dir, Vector3dc up, Matrix3d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix3d dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
, y
and z
+ * @return dest
+ */
+ Vector3d getScale(Vector3d dest);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3d inv = new Matrix3d(this).invert();
+ * inv.transform(dir.set(0, 0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveZ(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d positiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3d inv = new Matrix3d(this).transpose();
+ * inv.transform(dir.set(0, 0, 1));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d normalizedPositiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3d inv = new Matrix3d(this).invert();
+ * inv.transform(dir.set(1, 0, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d positiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3d inv = new Matrix3d(this).transpose();
+ * inv.transform(dir.set(1, 0, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d normalizedPositiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3d inv = new Matrix3d(this).invert();
+ * inv.transform(dir.set(0, 1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d positiveY(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3d inv = new Matrix3d(this).transpose();
+ * inv.transform(dir.set(0, 1, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d normalizedPositiveY(Vector3d dir);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d add(Matrix3dc other, Matrix3d dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d sub(Matrix3dc subtrahend, Matrix3d dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mulComponentWise(Matrix3dc other, Matrix3d dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d lerp(Matrix3dc other, double t, Matrix3d dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix3d().lookAlong(new Vector3d(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(double, double, double, double, double, double, Matrix3d)
+ *
+ * @param direction
+ * the direction to rotate towards
+ * @param up
+ * the model's up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateTowards(Vector3dc direction, Vector3dc up, Matrix3d dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix3d().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc, Matrix3d)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix3d dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by this
matrix and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that this
matrix only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order X * Y * Z
to obtain the identical matrix.
+ * This means that calling {@link Matrix3dc#rotateXYZ(double, double, double, Matrix3d)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix3d m = ...; // <- matrix only representing rotation
+ * Matrix3d n = new Matrix3d();
+ * n.rotateXYZ(m.getEulerAnglesXYZ(new Vector3d()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3d getEulerAnglesXYZ(Vector3d dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by this
matrix and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that this
matrix only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order Z * Y * X
to obtain the identical matrix.
+ * This means that calling {@link Matrix3dc#rotateZYX(double, double, double, Matrix3d)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix3d m = ...; // <- matrix only representing rotation
+ * Matrix3d n = new Matrix3d();
+ * n.rotateZYX(m.getEulerAnglesZYX(new Vector3d()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3d getEulerAnglesZYX(Vector3d dest);
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a
+ * 0 1 b
+ * 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d obliqueZ(double a, double b, Matrix3d dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix3dc m, double delta);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal (nx, ny, nz)
, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3d reflect(double nx, double ny, double nz, Matrix3d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through a plane
+ * specified via the plane orientation, and store the result in dest
.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3d reflect(Quaterniondc orientation, Matrix3d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3d reflect(Vector3dc normal, Matrix3d dest);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compute (x, y, z)^T * this * (x, y, z)
.
+ *
+ * @param x
+ * the x coordinate of the vector to multiply
+ * @param y
+ * the y coordinate of the vector to multiply
+ * @param z
+ * the z coordinate of the vector to multiply
+ * @return the result
+ */
+ double quadraticFormProduct(double x, double y, double z);
+
+ /**
+ * Compute v^T * this * v
.
+ *
+ * @param v
+ * the vector to multiply
+ * @return the result
+ */
+ double quadraticFormProduct(Vector3dc v);
+
+ /**
+ * Compute v^T * this * v
.
+ *
+ * @param v
+ * the vector to multiply
+ * @return the result
+ */
+ double quadraticFormProduct(Vector3fc v);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapXZY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapXZnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapXnYnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapXnZY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapXnZnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYXZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYXnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYZX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYZnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYnXZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYnXnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYnZX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapYnZnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZXY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZXnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZYX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZYnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZnXY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZnXnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZnYX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapZnYnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXYnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXZY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXZnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXnYZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXnYnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXnZY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnXnZnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYXZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYXnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYZX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYZnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYnXZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYnXnZ(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYnZX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnYnZnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZXY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZXnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZYX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZYnX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZnXY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZnXnY(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZnYX(Matrix3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d mapnZnYnX(Matrix3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d negateX(Matrix3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d negateY(Matrix3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d negateZ(Matrix3d dest);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3f.java
new file mode 100644
index 000000000..751127974
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3f.java
@@ -0,0 +1,4920 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+
+/**
+ * Contains the definition of a 3x3 matrix of floats, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20
+ * m01 m11 m21
+ * m02 m12 m22
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Matrix3f implements Externalizable, Cloneable, Matrix3fc {
+
+ private static final long serialVersionUID = 1L;
+
+ public float m00, m01, m02;
+ public float m10, m11, m12;
+ public float m20, m21, m22;
+
+ /**
+ * Create a new {@link Matrix3f} and set it to {@link #identity() identity}.
+ */
+ public Matrix3f() {
+ m00 = 1.0f;
+ m11 = 1.0f;
+ m22 = 1.0f;
+ }
+
+ /**
+ * Create a new {@link Matrix3f} by setting its uppper left 2x2 submatrix to the values of the given {@link Matrix2fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix2fc}
+ */
+ public Matrix3f(Matrix2fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3f} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix3fc} to copy the values from
+ */
+ public Matrix3f(Matrix3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix3f} and make it a copy of the upper left 3x3 of the given {@link Matrix4fc}.
+ *
+ * @param mat
+ * the {@link Matrix4fc} to copy the values from
+ */
+ public Matrix3f(Matrix4fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new 3x3 matrix using the supplied float values. The order of the parameter is column-major,
+ * so the first three parameters specify the three elements of the first column.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m02
+ * the value of m02
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m12
+ * the value of m12
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ * @param m22
+ * the value of m22
+ */
+ public Matrix3f(float m00, float m01, float m02,
+ float m10, float m11, float m12,
+ float m20, float m21, float m22) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ }
+
+ /**
+ * Create a new {@link Matrix3f} by reading its 9 float components from the given {@link FloatBuffer}
+ * at the buffer's current position.
+ *
+ * That FloatBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link FloatBuffer} to read the matrix values from
+ */
+ public Matrix3f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Matrix3f} and initialize its three columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ */
+ public Matrix3f(Vector3fc col0, Vector3fc col1, Vector3fc col2) {
+ set(col0, col1, col2);
+ }
+
+ public float m00() {
+ return m00;
+ }
+ public float m01() {
+ return m01;
+ }
+ public float m02() {
+ return m02;
+ }
+ public float m10() {
+ return m10;
+ }
+ public float m11() {
+ return m11;
+ }
+ public float m12() {
+ return m12;
+ }
+ public float m20() {
+ return m20;
+ }
+ public float m21() {
+ return m21;
+ }
+ public float m22() {
+ return m22;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix3f m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix3f m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ public Matrix3f m02(float m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix3f m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix3f m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ public Matrix3f m12(float m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ public Matrix3f m20(float m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ public Matrix3f m21(float m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ public Matrix3f m22(float m22) {
+ this.m22 = m22;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix3f _m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix3f _m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ Matrix3f _m02(float m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix3f _m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix3f _m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ Matrix3f _m12(float m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix3f _m20(float m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix3f _m21(float m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ Matrix3f _m22(float m22) {
+ this.m22 = m22;
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the ones in m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix3f set(Matrix3fc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22());
+ }
+
+ /**
+ * Store the values of the transpose of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the transposed values from
+ * @return this
+ */
+ public Matrix3f setTransposed(Matrix3fc m) {
+ float nm10 = m.m01(), nm12 = m.m21();
+ float nm20 = m.m02(), nm21 = m.m12();
+ return this
+ ._m00(m.m00())._m01(m.m10())._m02(m.m20())
+ ._m10(nm10)._m11(m.m11())._m12(nm12)
+ ._m20(nm20)._m21(nm21)._m22(m.m22());
+ }
+
+ /**
+ * Set the elements of this matrix to the left 3x3 submatrix of m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix3f set(Matrix4x3fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the upper left 3x3 of the given {@link Matrix4fc}.
+ *
+ * @param mat
+ * the {@link Matrix4fc} to copy the values from
+ * @return this
+ */
+ public Matrix3f set(Matrix4fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ return this;
+ }
+
+ /**
+ * Set the upper left 2x2 submatrix of this {@link Matrix3f} to the given {@link Matrix2fc}
+ * and the rest to identity.
+ *
+ * @see #Matrix3f(Matrix2fc)
+ *
+ * @param mat
+ * the {@link Matrix2fc}
+ * @return this
+ */
+ public Matrix3f set(Matrix2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = 0.0f;
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = 0.0f;
+ m20 = 0.0f;
+ m21 = 0.0f;
+ m22 = 1.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Matrix3f set(AxisAngle4f axisAngle) {
+ float x = axisAngle.x;
+ float y = axisAngle.y;
+ float z = axisAngle.z;
+ float angle = axisAngle.angle;
+ float invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ float s = Math.sin(angle);
+ float c = Math.cosFromSin(s, angle);
+ float omc = 1.0f - c;
+ m00 = c + x*x*omc;
+ m11 = c + y*y*omc;
+ m22 = c + z*z*omc;
+ float tmp1 = x*y*omc;
+ float tmp2 = z*s;
+ m10 = tmp1 - tmp2;
+ m01 = tmp1 + tmp2;
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = tmp1 + tmp2;
+ m02 = tmp1 - tmp2;
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = tmp1 - tmp2;
+ m12 = tmp1 + tmp2;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Matrix3f set(AxisAngle4d axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0f - c;
+ m00 = (float)(c + x*x*omc);
+ m11 = (float)(c + y*y*omc);
+ m22 = (float)(c + z*z*omc);
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ m10 = (float)(tmp1 - tmp2);
+ m01 = (float)(tmp1 + tmp2);
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = (float)(tmp1 + tmp2);
+ m02 = (float)(tmp1 - tmp2);
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = (float)(tmp1 - tmp2);
+ m12 = (float)(tmp1 + tmp2);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaternionfc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param q
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3f set(Quaternionfc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Set this matrix to a rotation - and possibly scaling - equivalent to the given quaternion.
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @param q
+ * the quaternion
+ * @return this
+ */
+ public Matrix3f set(Quaterniondc q) {
+ double w2 = q.w() * q.w();
+ double x2 = q.x() * q.x();
+ double y2 = q.y() * q.y();
+ double z2 = q.z() * q.z();
+ double zw = q.z() * q.w();
+ double xy = q.x() * q.y();
+ double xz = q.x() * q.z();
+ double yw = q.y() * q.w();
+ double yz = q.y() * q.z();
+ double xw = q.x() * q.w();
+ m00 = (float) (w2 + x2 - z2 - y2);
+ m01 = (float) (xy + zw + zw + xy);
+ m02 = (float) (xz - yw + xz - yw);
+ m10 = (float) (-zw + xy - zw + xy);
+ m11 = (float) (y2 - z2 + w2 - x2);
+ m12 = (float) (yz + yz + xw + xw);
+ m20 = (float) (yw + xz + xz + yw);
+ m21 = (float) (yz + yz - xw - xw);
+ m22 = (float) (z2 - y2 - x2 + w2);
+ return this;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3f mul(Matrix3fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix3f mul(Matrix3fc right, Matrix3f dest) {
+ float nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ float nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ float nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ float nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ float nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ float nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ float nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ float nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ float nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3f mulLocal(Matrix3fc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix3f mulLocal(Matrix3fc left, Matrix3f dest) {
+ float nm00 = left.m00() * m00 + left.m10() * m01 + left.m20() * m02;
+ float nm01 = left.m01() * m00 + left.m11() * m01 + left.m21() * m02;
+ float nm02 = left.m02() * m00 + left.m12() * m01 + left.m22() * m02;
+ float nm10 = left.m00() * m10 + left.m10() * m11 + left.m20() * m12;
+ float nm11 = left.m01() * m10 + left.m11() * m11 + left.m21() * m12;
+ float nm12 = left.m02() * m10 + left.m12() * m11 + left.m22() * m12;
+ float nm20 = left.m00() * m20 + left.m10() * m21 + left.m20() * m22;
+ float nm21 = left.m01() * m20 + left.m11() * m21 + left.m21() * m22;
+ float nm22 = left.m02() * m20 + left.m12() * m21 + left.m22() * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied float values. The result looks like this:
+ *
+ * m00, m10, m20
+ * m01, m11, m21
+ * m02, m12, m22
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m02
+ * the new value of m02
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m12
+ * the new value of m12
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @param m22
+ * the new value of m22
+ * @return this
+ */
+ public Matrix3f set(float m00, float m01, float m02,
+ float m10, float m11, float m12,
+ float m20, float m21, float m22) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied float array. The result looks like this:
+ *
+ * 0, 3, 6
+ * 1, 4, 7
+ * 2, 5, 8
+ *
+ * This method only uses the first 9 values, all others are ignored.
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix3f set(float m[]) {
+ MemUtil.INSTANCE.copy(m, 0, this);
+ return this;
+ }
+
+ /**
+ * Set the three columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @return this
+ */
+ public Matrix3f set(Vector3fc col0, Vector3fc col1, Vector3fc col2) {
+ this.m00 = col0.x();
+ this.m01 = col0.y();
+ this.m02 = col0.z();
+ this.m10 = col1.x();
+ this.m11 = col1.y();
+ this.m12 = col1.z();
+ this.m20 = col2.x();
+ this.m21 = col2.y();
+ this.m22 = col2.z();
+ return this;
+ }
+
+ public float determinant() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * @return this
+ */
+ public Matrix3f invert() {
+ return invert(this);
+ }
+
+ public Matrix3f invert(Matrix3f dest) {
+ float a = Math.fma(m00, m11, -m01 * m10);
+ float b = Math.fma(m02, m10, -m00 * m12);
+ float c = Math.fma(m01, m12, -m02 * m11);
+ float d = Math.fma(a, m22, Math.fma(b, m21, c * m20));
+ float s = 1.0f / d;
+ float nm00 = Math.fma(m11, m22, -m21 * m12) * s;
+ float nm01 = Math.fma(m21, m02, -m01 * m22) * s;
+ float nm02 = c * s;
+ float nm10 = Math.fma(m20, m12, -m10 * m22) * s;
+ float nm11 = Math.fma(m00, m22, -m20 * m02) * s;
+ float nm12 = b * s;
+ float nm20 = Math.fma(m10, m21, -m20 * m11) * s;
+ float nm21 = Math.fma(m20, m01, -m00 * m21) * s;
+ float nm22 = a * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this
+ */
+ public Matrix3f transpose() {
+ return transpose(this);
+ }
+
+ public Matrix3f transpose(Matrix3f dest) {
+ return dest.set(m00, m10, m20,
+ m01, m11, m21,
+ m02, m12, m22);
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + "\n"
+ + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix3fc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix3fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix3f get(Matrix3f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4f get(Matrix4f dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4f getRotation(AxisAngle4f dest) {
+ return dest.set(this);
+ }
+
+ public Quaternionf getUnnormalizedRotation(Quaternionf dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaternionf getNormalizedRotation(Quaternionf dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaterniond getNormalizedRotation(Quaterniond dest) {
+ return dest.setFromNormalized(this);
+ }
+
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get3x4(FloatBuffer buffer) {
+ return get3x4(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get3x4(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get3x4(ByteBuffer buffer) {
+ return get3x4(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get3x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer getTransposed(FloatBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public FloatBuffer getTransposed(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public Matrix3fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public float[] get(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ public float[] get(float[] arr) {
+ return get(arr, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 9 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+ /**
+ * Set the values of this matrix by reading 9 float values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set all values within this matrix to zero.
+ *
+ * @return this
+ */
+ public Matrix3f zero() {
+ MemUtil.INSTANCE.zero(this);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the identity.
+ *
+ * @return this
+ */
+ public Matrix3f identity() {
+ MemUtil.INSTANCE.identity(this);
+ return this;
+ }
+
+ public Matrix3f scale(Vector3fc xyz, Matrix3f dest) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @return this
+ */
+ public Matrix3f scale(Vector3fc xyz) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), this);
+ }
+
+ public Matrix3f scale(float x, float y, float z, Matrix3f dest) {
+ // scale matrix elements:
+ // m00 = x, m11 = y, m22 = z
+ // all others = 0
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m02 = m02 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ dest.m12 = m12 * y;
+ dest.m20 = m20 * z;
+ dest.m21 = m21 * z;
+ dest.m22 = m22 * z;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix3f scale(float x, float y, float z) {
+ return scale(x, y, z, this);
+ }
+
+ public Matrix3f scale(float xyz, Matrix3f dest) {
+ return scale(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(float, float, float)
+ *
+ * @param xyz
+ * the factor for all components
+ * @return this
+ */
+ public Matrix3f scale(float xyz) {
+ return scale(xyz, xyz, xyz);
+ }
+
+ public Matrix3f scaleLocal(float x, float y, float z, Matrix3f dest) {
+ float nm00 = x * m00;
+ float nm01 = y * m01;
+ float nm02 = z * m02;
+ float nm10 = x * m10;
+ float nm11 = y * m11;
+ float nm12 = z * m12;
+ float nm20 = x * m20;
+ float nm21 = y * m21;
+ float nm22 = z * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix3f scaleLocal(float x, float y, float z) {
+ return scaleLocal(x, y, z, this);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(float) scale()} instead.
+ *
+ * @see #scale(float)
+ *
+ * @param factor
+ * the scale factor in x, y and z
+ * @return this
+ */
+ public Matrix3f scaling(float factor) {
+ MemUtil.INSTANCE.zero(this);
+ m00 = factor;
+ m11 = factor;
+ m22 = factor;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @param z
+ * the scale in z
+ * @return this
+ */
+ public Matrix3f scaling(float x, float y, float z) {
+ MemUtil.INSTANCE.zero(this);
+ m00 = x;
+ m11 = y;
+ m22 = z;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by xyz.x
, xyz.y
and xyz.z
respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector3fc) scale()} instead.
+ *
+ * @see #scale(Vector3fc)
+ *
+ * @param xyz
+ * the scale in x, y and z respectively
+ * @return this
+ */
+ public Matrix3f scaling(Vector3fc xyz) {
+ return scaling(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(float, Vector3fc) rotate()} instead.
+ *
+ * @see #rotate(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3f rotation(float angle, Vector3fc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4f) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3f rotation(AxisAngle4f axisAngle) {
+ return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(float, float, float, float) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the rotation axis
+ * @param y
+ * the y-component of the rotation axis
+ * @param z
+ * the z-component of the rotation axis
+ * @return this
+ */
+ public Matrix3f rotation(float angle, float x, float y, float z) {
+ float sin = Math.sin(angle);
+ float cos = Math.cosFromSin(sin, angle);
+ float C = 1.0f - cos;
+ float xy = x * y, xz = x * z, yz = y * z;
+ m00 = cos + x * x * C;
+ m10 = xy * C - z * sin;
+ m20 = xz * C + y * sin;
+ m01 = xy * C + z * sin;
+ m11 = cos + y * y * C;
+ m21 = yz * C - x * sin;
+ m02 = xz * C - y * sin;
+ m12 = yz * C + x * sin;
+ m22 = cos + z * z * C;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3f rotationX(float ang) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = 1.0f;
+ m01 = 0.0f;
+ m02 = 0.0f;
+ m10 = 0.0f;
+ m11 = cos;
+ m12 = sin;
+ m20 = 0.0f;
+ m21 = -sin;
+ m22 = cos;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3f rotationY(float ang) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = 0.0f;
+ m02 = -sin;
+ m10 = 0.0f;
+ m11 = 1.0f;
+ m12 = 0.0f;
+ m20 = sin;
+ m21 = 0.0f;
+ m22 = cos;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3f rotationZ(float ang) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = sin;
+ m02 = 0.0f;
+ m10 = -sin;
+ m11 = cos;
+ m12 = 0.0f;
+ m20 = 0.0f;
+ m21 = 0.0f;
+ m22 = 1.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3f rotationXYZ(float angleX, float angleY, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm11 = cosX;
+ float nm12 = sinX;
+ float nm21 = m_sinX;
+ float nm22 = cosX;
+ // rotateY
+ float nm00 = cosY;
+ float nm01 = nm21 * m_sinY;
+ float nm02 = nm22 * m_sinY;
+ m20 = sinY;
+ m21 = nm21 * cosY;
+ m22 = nm22 * cosY;
+ // rotateZ
+ m00 = nm00 * cosZ;
+ m01 = nm01 * cosZ + nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ;
+ m11 = nm01 * m_sinZ + nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix3f rotationZYX(float angleZ, float angleY, float angleX) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = cosZ;
+ float nm01 = sinZ;
+ float nm10 = m_sinZ;
+ float nm11 = cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY;
+ float nm21 = nm01 * sinY;
+ float nm22 = cosY;
+ m00 = nm00 * cosY;
+ m01 = nm01 * cosY;
+ m02 = m_sinY;
+ // rotateX
+ m10 = nm10 * cosX + nm20 * sinX;
+ m11 = nm11 * cosX + nm21 * sinX;
+ m12 = nm22 * sinX;
+ m20 = nm10 * m_sinX + nm20 * cosX;
+ m21 = nm11 * m_sinX + nm21 * cosX;
+ m22 = nm22 * cosX;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3f rotationYXZ(float angleY, float angleX, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm00 = cosY;
+ float nm02 = m_sinY;
+ float nm20 = sinY;
+ float nm22 = cosY;
+ // rotateX
+ float nm10 = nm20 * sinX;
+ float nm11 = cosX;
+ float nm12 = nm22 * sinX;
+ m20 = nm20 * cosX;
+ m21 = m_sinX;
+ m22 = nm22 * cosX;
+ // rotateZ
+ m00 = nm00 * cosZ + nm10 * sinZ;
+ m01 = nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ + nm10 * cosZ;
+ m11 = nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return this;
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaternionfc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaternionfc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3f rotation(Quaternionfc quat) {
+ float w2 = quat.w() * quat.w();
+ float x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y();
+ float z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw;
+ float xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz;
+ float yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz;
+ float xw = quat.x() * quat.w(), dxw = xw + xw;
+ m00 = w2 + x2 - z2 - y2;
+ m01 = dxy + dzw;
+ m02 = dxz - dyw;
+ m10 = -dzw + dxy;
+ m11 = y2 - z2 + w2 - x2;
+ m12 = dyz + dxw;
+ m20 = dyw + dxz;
+ m21 = dyz - dxw;
+ m22 = z2 - y2 - x2 + w2;
+ return this;
+ }
+
+ public Vector3f transform(Vector3f v) {
+ return v.mul(this);
+ }
+
+ public Vector3f transform(Vector3fc v, Vector3f dest) {
+ return v.mul(this, dest);
+ }
+
+ public Vector3f transform(float x, float y, float z, Vector3f dest) {
+ return dest.set(Math.fma(m00, x, Math.fma(m10, y, m20 * z)),
+ Math.fma(m01, x, Math.fma(m11, y, m21 * z)),
+ Math.fma(m02, x, Math.fma(m12, y, m22 * z)));
+ }
+
+ public Vector3f transformTranspose(Vector3f v) {
+ return v.mulTranspose(this);
+ }
+
+ public Vector3f transformTranspose(Vector3fc v, Vector3f dest) {
+ return v.mulTranspose(this, dest);
+ }
+
+ public Vector3f transformTranspose(float x, float y, float z, Vector3f dest) {
+ return dest.set(Math.fma(m00, x, Math.fma(m01, y, m02 * z)),
+ Math.fma(m10, x, Math.fma(m11, y, m12 * z)),
+ Math.fma(m20, x, Math.fma(m21, y, m22 * z)));
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(m00);
+ out.writeFloat(m01);
+ out.writeFloat(m02);
+ out.writeFloat(m10);
+ out.writeFloat(m11);
+ out.writeFloat(m12);
+ out.writeFloat(m20);
+ out.writeFloat(m21);
+ out.writeFloat(m22);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readFloat();
+ m01 = in.readFloat();
+ m02 = in.readFloat();
+ m10 = in.readFloat();
+ m11 = in.readFloat();
+ m12 = in.readFloat();
+ m20 = in.readFloat();
+ m21 = in.readFloat();
+ m22 = in.readFloat();
+ }
+
+ public Matrix3f rotateX(float ang, Matrix3f dest) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ float rm11 = cos;
+ float rm21 = -sin;
+ float rm12 = sin;
+ float rm22 = cos;
+
+ // add temporaries for dependent values
+ float nm10 = m10 * rm11 + m20 * rm12;
+ float nm11 = m11 * rm11 + m21 * rm12;
+ float nm12 = m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m10 * rm21 + m20 * rm22;
+ dest.m21 = m11 * rm21 + m21 * rm22;
+ dest.m22 = m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3f rotateX(float ang) {
+ return rotateX(ang, this);
+ }
+
+ public Matrix3f rotateY(float ang, Matrix3f dest) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ float rm00 = cos;
+ float rm20 = sin;
+ float rm02 = -sin;
+ float rm22 = cos;
+
+ // add temporaries for dependent values
+ float nm00 = m00 * rm00 + m20 * rm02;
+ float nm01 = m01 * rm00 + m21 * rm02;
+ float nm02 = m02 * rm00 + m22 * rm02;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3f rotateY(float ang) {
+ return rotateY(ang, this);
+ }
+
+ public Matrix3f rotateZ(float ang, Matrix3f dest) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ float rm00 = cos;
+ float rm10 = -sin;
+ float rm01 = sin;
+ float rm11 = cos;
+
+ // add temporaries for dependent values
+ float nm00 = m00 * rm00 + m10 * rm01;
+ float nm01 = m01 * rm00 + m11 * rm01;
+ float nm02 = m02 * rm00 + m12 * rm01;
+ // set non-dependent values directly
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m12 = m02 * rm10 + m12 * rm11;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3f rotateZ(float ang) {
+ return rotateZ(ang, this);
+ }
+
+ /**
+ * Apply rotation of angles.x
radians about the X axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix3f rotateXYZ(Vector3f angles) {
+ return rotateXYZ(angles.x, angles.y, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3f rotateXYZ(float angleX, float angleY, float angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix3f rotateXYZ(float angleX, float angleY, float angleZ, Matrix3f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm10 = m10 * cosX + m20 * sinX;
+ float nm11 = m11 * cosX + m21 * sinX;
+ float nm12 = m12 * cosX + m22 * sinX;
+ float nm20 = m10 * m_sinX + m20 * cosX;
+ float nm21 = m11 * m_sinX + m21 * cosX;
+ float nm22 = m12 * m_sinX + m22 * cosX;
+ // rotateY
+ float nm00 = m00 * cosY + nm20 * m_sinY;
+ float nm01 = m01 * cosY + nm21 * m_sinY;
+ float nm02 = m02 * cosY + nm22 * m_sinY;
+ dest.m20 = m00 * sinY + nm20 * cosY;
+ dest.m21 = m01 * sinY + nm21 * cosY;
+ dest.m22 = m02 * sinY + nm22 * cosY;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.z
radians about the Z axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.x
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix3f rotateZYX(Vector3f angles) {
+ return rotateZYX(angles.z, angles.y, angles.x);
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix3f rotateZYX(float angleZ, float angleY, float angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix3f rotateZYX(float angleZ, float angleY, float angleX, Matrix3f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = m00 * cosZ + m10 * sinZ;
+ float nm01 = m01 * cosZ + m11 * sinZ;
+ float nm02 = m02 * cosZ + m12 * sinZ;
+ float nm10 = m00 * m_sinZ + m10 * cosZ;
+ float nm11 = m01 * m_sinZ + m11 * cosZ;
+ float nm12 = m02 * m_sinZ + m12 * cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY + m20 * cosY;
+ float nm21 = nm01 * sinY + m21 * cosY;
+ float nm22 = nm02 * sinY + m22 * cosY;
+ dest.m00 = nm00 * cosY + m20 * m_sinY;
+ dest.m01 = nm01 * cosY + m21 * m_sinY;
+ dest.m02 = nm02 * cosY + m22 * m_sinY;
+ // rotateX
+ dest.m10 = nm10 * cosX + nm20 * sinX;
+ dest.m11 = nm11 * cosX + nm21 * sinX;
+ dest.m12 = nm12 * cosX + nm22 * sinX;
+ dest.m20 = nm10 * m_sinX + nm20 * cosX;
+ dest.m21 = nm11 * m_sinX + nm21 * cosX;
+ dest.m22 = nm12 * m_sinX + nm22 * cosX;
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.y
radians about the Y axis, followed by a rotation of angles.x
radians about the X axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix3f rotateYXZ(Vector3f angles) {
+ return rotateYXZ(angles.y, angles.x, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix3f rotateYXZ(float angleY, float angleX, float angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix3f rotateYXZ(float angleY, float angleX, float angleZ, Matrix3f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm20 = m00 * sinY + m20 * cosY;
+ float nm21 = m01 * sinY + m21 * cosY;
+ float nm22 = m02 * sinY + m22 * cosY;
+ float nm00 = m00 * cosY + m20 * m_sinY;
+ float nm01 = m01 * cosY + m21 * m_sinY;
+ float nm02 = m02 * cosY + m22 * m_sinY;
+ // rotateX
+ float nm10 = m10 * cosX + nm20 * sinX;
+ float nm11 = m11 * cosX + nm21 * sinX;
+ float nm12 = m12 * cosX + nm22 * sinX;
+ dest.m20 = m10 * m_sinX + nm20 * cosX;
+ dest.m21 = m11 * m_sinX + nm21 * cosX;
+ dest.m22 = m12 * m_sinX + nm22 * cosX;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix3f rotate(float ang, float x, float y, float z) {
+ return rotate(ang, x, y, z, this);
+ }
+
+ public Matrix3f rotate(float ang, float x, float y, float z, Matrix3f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+
+ // rotation matrix elements:
+ // m30, m31, m32, m03, m13, m23 = 0
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float rm00 = xx * C + c;
+ float rm01 = xy * C + z * s;
+ float rm02 = xz * C - y * s;
+ float rm10 = xy * C - z * s;
+ float rm11 = yy * C + c;
+ float rm12 = yz * C + x * s;
+ float rm20 = xz * C + y * s;
+ float rm21 = yz * C - x * s;
+ float rm22 = zz * C + c;
+
+ // add temporaries for dependent values
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateLocal(float ang, float x, float y, float z, Matrix3f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float lm00 = xx * C + c;
+ float lm01 = xy * C + z * s;
+ float lm02 = xz * C - y * s;
+ float lm10 = xy * C - z * s;
+ float lm11 = yy * C + c;
+ float lm12 = yz * C + x * s;
+ float lm20 = xz * C + y * s;
+ float lm21 = yz * C - x * s;
+ float lm22 = zz * C + c;
+ float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix3f rotateLocal(float ang, float x, float y, float z) {
+ return rotateLocal(ang, x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(float) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateLocalX(float ang, Matrix3f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm01 = cos * m01 - sin * m02;
+ float nm02 = sin * m01 + cos * m02;
+ float nm11 = cos * m11 - sin * m12;
+ float nm12 = sin * m11 + cos * m12;
+ float nm21 = cos * m21 - sin * m22;
+ float nm22 = sin * m21 + cos * m22;
+ dest.m00 = m00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = m20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(float) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix3f rotateLocalX(float ang) {
+ return rotateLocalX(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateLocalY(float ang, Matrix3f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm00 = cos * m00 + sin * m02;
+ float nm02 = -sin * m00 + cos * m02;
+ float nm10 = cos * m10 + sin * m12;
+ float nm12 = -sin * m10 + cos * m12;
+ float nm20 = cos * m20 + sin * m22;
+ float nm22 = -sin * m20 + cos * m22;
+ dest.m00 = nm00;
+ dest.m01 = m01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = m11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = m21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @return this
+ */
+ public Matrix3f rotateLocalY(float ang) {
+ return rotateLocalY(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(float) rotationZ()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationZ(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateLocalZ(float ang, Matrix3f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm00 = cos * m00 - sin * m01;
+ float nm01 = sin * m00 + cos * m01;
+ float nm10 = cos * m10 - sin * m11;
+ float nm11 = sin * m10 + cos * m11;
+ float nm20 = cos * m20 - sin * m21;
+ float nm21 = sin * m20 + cos * m21;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = m02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = m12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = m22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @return this
+ */
+ public Matrix3f rotateLocalZ(float ang) {
+ return rotateLocalZ(ang, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3f rotate(Quaternionfc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotate(Quaternionfc quat, Matrix3f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = dxy - dzw;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateLocal(Quaternionfc quat, Matrix3f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float lm00 = w2 + x2 - z2 - y2;
+ float lm01 = dxy + dzw;
+ float lm02 = dxz - dyw;
+ float lm10 = dxy - dzw;
+ float lm11 = y2 - z2 + w2 - x2;
+ float lm12 = dyz + dxw;
+ float lm20 = dyw + dxz;
+ float lm21 = dyz - dxw;
+ float lm22 = z2 - y2 - x2 + w2;
+ float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix3f rotateLocal(Quaternionfc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3f rotate(AxisAngle4f axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotate(AxisAngle4f axisAngle, Matrix3f dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(float, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix3f rotate(float angle, Vector3fc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(float, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotate(float angle, Vector3fc axis, Matrix3f dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}.
+ *
+ * @see #lookAlong(float, float, float, float, float, float)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix3f lookAlong(Vector3fc dir, Vector3fc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}.
+ *
+ * @see #lookAlong(float, float, float, float, float, float)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f lookAlong(Vector3fc dir, Vector3fc up, Matrix3f dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()}
+ *
+ * @see #setLookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f lookAlong(float dirX, float dirY, float dirZ,
+ float upX, float upY, float upZ, Matrix3f dest) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm00 = leftX;
+ float rm01 = upnX;
+ float rm02 = dirX;
+ float rm10 = leftY;
+ float rm11 = upnY;
+ float rm12 = dirY;
+ float rm20 = leftZ;
+ float rm21 = upnZ;
+ float rm22 = dirZ;
+
+ // perform optimized matrix multiplication
+ // introduce temporaries for dependent results
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()}
+ *
+ * @see #setLookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3f lookAlong(float dirX, float dirY, float dirZ,
+ float upX, float upY, float upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(Vector3fc, Vector3fc)}.
+ *
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ * @see #lookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix3f setLookAlong(Vector3fc dir, Vector3fc up) {
+ return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(float, float, float, float, float, float) lookAlong()}
+ *
+ * @see #setLookAlong(float, float, float, float, float, float)
+ * @see #lookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3f setLookAlong(float dirX, float dirY, float dirZ,
+ float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+
+ return this;
+ }
+
+ public Vector3f getRow(int row, Vector3f dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ return dest.set(m00, m10, m20);
+ case 1:
+ return dest.set(m01, m11, m21);
+ case 2:
+ return dest.set(m02, m12, m22);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ public Matrix3f setRow(int row, Vector3fc src) throws IndexOutOfBoundsException {
+ return setRow(row, src.x(), src.y(), src.z());
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param x
+ * the first element in the row
+ * @param y
+ * the second element in the row
+ * @param z
+ * the third element in the row
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ public Matrix3f setRow(int row, float x, float y, float z) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ this.m00 = x;
+ this.m10 = y;
+ this.m20 = z;
+ break;
+ case 1:
+ this.m01 = x;
+ this.m11 = y;
+ this.m21 = z;
+ break;
+ case 2:
+ this.m02 = x;
+ this.m12 = y;
+ this.m22 = z;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ return dest.set(m00, m01, m02);
+ case 1:
+ return dest.set(m10, m11, m12);
+ case 2:
+ return dest.set(m20, m21, m22);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ public Matrix3f setColumn(int column, Vector3fc src) throws IndexOutOfBoundsException {
+ return setColumn(column, src.x(), src.y(), src.z());
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param x
+ * the first element in the column
+ * @param y
+ * the second element in the column
+ * @param z
+ * the third element in the column
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ public Matrix3f setColumn(int column, float x, float y, float z) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ this.m00 = x;
+ this.m01 = y;
+ this.m02 = z;
+ break;
+ case 1:
+ this.m10 = x;
+ this.m11 = y;
+ this.m12 = z;
+ break;
+ case 2:
+ this.m20 = x;
+ this.m21 = y;
+ this.m22 = z;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return this;
+ }
+
+ public float get(int column, int row) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given column and row to the specified value.
+ *
+ * @param column
+ * the colum index in [0..2]
+ * @param row
+ * the row index in [0..2]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix3f set(int column, int row, float value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ public float getRowColumn(int row, int column) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given row and column to the specified value.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param column
+ * the colum index in [0..2]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix3f setRowColumn(int row, int column, float value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ /**
+ * Set this
matrix to its own normal matrix.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix3fc)} to set a given Matrix3f to this matrix.
+ *
+ * @see #set(Matrix3fc)
+ *
+ * @return this
+ */
+ public Matrix3f normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In this case, use {@link #set(Matrix3fc)} to set a given Matrix3f to this matrix.
+ *
+ * @see #set(Matrix3fc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f normal(Matrix3f dest) {
+ float m00m11 = m00 * m11;
+ float m01m10 = m01 * m10;
+ float m02m10 = m02 * m10;
+ float m00m12 = m00 * m12;
+ float m01m12 = m01 * m12;
+ float m02m11 = m02 * m11;
+ float det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ float s = 1.0f / det;
+ /* Invert and transpose in one go */
+ float nm00 = (m11 * m22 - m21 * m12) * s;
+ float nm01 = (m20 * m12 - m10 * m22) * s;
+ float nm02 = (m10 * m21 - m20 * m11) * s;
+ float nm10 = (m21 * m02 - m01 * m22) * s;
+ float nm11 = (m00 * m22 - m20 * m02) * s;
+ float nm12 = (m20 * m01 - m00 * m21) * s;
+ float nm20 = (m01m12 - m02m11) * s;
+ float nm21 = (m02m10 - m00m12) * s;
+ float nm22 = (m00m11 - m01m10) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ /**
+ * Compute the cofactor matrix of this
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal()} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @return this
+ */
+ public Matrix3f cofactor() {
+ return cofactor(this);
+ }
+
+ /**
+ * Compute the cofactor matrix of this
and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f cofactor(Matrix3f dest) {
+ float nm00 = m11 * m22 - m21 * m12;
+ float nm01 = m20 * m12 - m10 * m22;
+ float nm02 = m10 * m21 - m20 * m11;
+ float nm10 = m21 * m02 - m01 * m22;
+ float nm11 = m00 * m22 - m20 * m02;
+ float nm12 = m20 * m01 - m00 * m21;
+ float nm20 = m01 * m12 - m11 * m02;
+ float nm21 = m02 * m10 - m12 * m00;
+ float nm22 = m00 * m11 - m10 * m01;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ return dest;
+ }
+
+ public Vector3f getScale(Vector3f dest) {
+ return dest.set(Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02),
+ Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12),
+ Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22));
+ }
+
+ public Vector3f positiveZ(Vector3f dir) {
+ dir.x = m10 * m21 - m11 * m20;
+ dir.y = m20 * m01 - m21 * m00;
+ dir.z = m00 * m11 - m01 * m10;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f normalizedPositiveZ(Vector3f dir) {
+ dir.x = m02;
+ dir.y = m12;
+ dir.z = m22;
+ return dir;
+ }
+
+ public Vector3f positiveX(Vector3f dir) {
+ dir.x = m11 * m22 - m12 * m21;
+ dir.y = m02 * m21 - m01 * m22;
+ dir.z = m01 * m12 - m02 * m11;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f normalizedPositiveX(Vector3f dir) {
+ dir.x = m00;
+ dir.y = m10;
+ dir.z = m20;
+ return dir;
+ }
+
+ public Vector3f positiveY(Vector3f dir) {
+ dir.x = m12 * m20 - m10 * m22;
+ dir.y = m00 * m22 - m02 * m20;
+ dir.z = m02 * m10 - m00 * m12;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f normalizedPositiveY(Vector3f dir) {
+ dir.x = m01;
+ dir.y = m11;
+ dir.z = m21;
+ return dir;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(m00);
+ result = prime * result + Float.floatToIntBits(m01);
+ result = prime * result + Float.floatToIntBits(m02);
+ result = prime * result + Float.floatToIntBits(m10);
+ result = prime * result + Float.floatToIntBits(m11);
+ result = prime * result + Float.floatToIntBits(m12);
+ result = prime * result + Float.floatToIntBits(m20);
+ result = prime * result + Float.floatToIntBits(m21);
+ result = prime * result + Float.floatToIntBits(m22);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Matrix3f other = (Matrix3f) obj;
+ if (Float.floatToIntBits(m00) != Float.floatToIntBits(other.m00))
+ return false;
+ if (Float.floatToIntBits(m01) != Float.floatToIntBits(other.m01))
+ return false;
+ if (Float.floatToIntBits(m02) != Float.floatToIntBits(other.m02))
+ return false;
+ if (Float.floatToIntBits(m10) != Float.floatToIntBits(other.m10))
+ return false;
+ if (Float.floatToIntBits(m11) != Float.floatToIntBits(other.m11))
+ return false;
+ if (Float.floatToIntBits(m12) != Float.floatToIntBits(other.m12))
+ return false;
+ if (Float.floatToIntBits(m20) != Float.floatToIntBits(other.m20))
+ return false;
+ if (Float.floatToIntBits(m21) != Float.floatToIntBits(other.m21))
+ return false;
+ if (Float.floatToIntBits(m22) != Float.floatToIntBits(other.m22))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix3fc m, float delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix3f))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m02, m.m02(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m12, m.m12(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ if (!Runtime.equals(m22, m.m22(), delta))
+ return false;
+ return true;
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix3f swap(Matrix3f other) {
+ MemUtil.INSTANCE.swap(this, other);
+ return this;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix3f add(Matrix3fc other) {
+ return add(other, this);
+ }
+
+ public Matrix3f add(Matrix3fc other, Matrix3f dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m02 = m02 + other.m02();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ dest.m12 = m12 + other.m12();
+ dest.m20 = m20 + other.m20();
+ dest.m21 = m21 + other.m21();
+ dest.m22 = m22 + other.m22();
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix3f sub(Matrix3fc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix3f sub(Matrix3fc subtrahend, Matrix3f dest) {
+ dest.m00 = m00 - subtrahend.m00();
+ dest.m01 = m01 - subtrahend.m01();
+ dest.m02 = m02 - subtrahend.m02();
+ dest.m10 = m10 - subtrahend.m10();
+ dest.m11 = m11 - subtrahend.m11();
+ dest.m12 = m12 - subtrahend.m12();
+ dest.m20 = m20 - subtrahend.m20();
+ dest.m21 = m21 - subtrahend.m21();
+ dest.m22 = m22 - subtrahend.m22();
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix3f mulComponentWise(Matrix3fc other) {
+ return mulComponentWise(other, this);
+ }
+
+ public Matrix3f mulComponentWise(Matrix3fc other, Matrix3f dest) {
+ dest.m00 = m00 * other.m00();
+ dest.m01 = m01 * other.m01();
+ dest.m02 = m02 * other.m02();
+ dest.m10 = m10 * other.m10();
+ dest.m11 = m11 * other.m11();
+ dest.m12 = m12 * other.m12();
+ dest.m20 = m20 * other.m20();
+ dest.m21 = m21 * other.m21();
+ dest.m22 = m22 * other.m22();
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a skew-symmetric matrix using the following layout:
+ *
+ * 0, a, -b
+ * -a, 0, c
+ * b, -c, 0
+ *
+ *
+ * Reference: https://en.wikipedia.org
+ *
+ * @param a
+ * the value used for the matrix elements m01 and m10
+ * @param b
+ * the value used for the matrix elements m02 and m20
+ * @param c
+ * the value used for the matrix elements m12 and m21
+ * @return this
+ */
+ public Matrix3f setSkewSymmetric(float a, float b, float c) {
+ m00 = m11 = m22 = 0;
+ m01 = -a;
+ m02 = b;
+ m10 = a;
+ m12 = -c;
+ m20 = -b;
+ m21 = c;
+ return this;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix3f lerp(Matrix3fc other, float t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix3f lerp(Matrix3fc other, float t, Matrix3f dest) {
+ dest.m00 = Math.fma(other.m00() - m00, t, m00);
+ dest.m01 = Math.fma(other.m01() - m01, t, m01);
+ dest.m02 = Math.fma(other.m02() - m02, t, m02);
+ dest.m10 = Math.fma(other.m10() - m10, t, m10);
+ dest.m11 = Math.fma(other.m11() - m11, t, m11);
+ dest.m12 = Math.fma(other.m12() - m12, t, m12);
+ dest.m20 = Math.fma(other.m20() - m20, t, m20);
+ dest.m21 = Math.fma(other.m21() - m21, t, m21);
+ dest.m22 = Math.fma(other.m22() - m22, t, m22);
+ return dest;
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3f().lookAlong(new Vector3f(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(float, float, float, float, float, float, Matrix3f)
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ *
+ * @param direction
+ * the direction to rotate towards
+ * @param up
+ * the model's up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateTowards(Vector3fc direction, Vector3fc up, Matrix3f dest) {
+ return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3f().lookAlong(new Vector3f(dir).negate(), up).invert())
+ *
+ * @see #rotateTowards(float, float, float, float, float, float)
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ *
+ * @param direction
+ * the direction to orient towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix3f rotateTowards(Vector3fc direction, Vector3fc up) {
+ return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3f().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert())
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix3f().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix3f dest) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ float rm00 = leftX;
+ float rm01 = leftY;
+ float rm02 = leftZ;
+ float rm10 = upnX;
+ float rm11 = upnY;
+ float rm12 = upnZ;
+ float rm20 = ndirX;
+ float rm21 = ndirY;
+ float rm22 = ndirZ;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with center - eye
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAlong(new Vector3f(dir).negate(), up).invert()
+ *
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ * @see #rotateTowards(float, float, float, float, float, float)
+ *
+ * @param dir
+ * the direction to orient the local -z axis towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix3f rotationTowards(Vector3fc dir, Vector3fc up) {
+ return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with center - eye
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert()
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix3f rotationTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ return this;
+ }
+
+ public Vector3f getEulerAnglesZYX(Vector3f dest) {
+ dest.x = Math.atan2(m12, m22);
+ dest.y = Math.atan2(-m02, Math.sqrt(1.0f - m02 * m02));
+ dest.z = Math.atan2(m01, m00);
+ return dest;
+ }
+
+ public Vector3f getEulerAnglesXYZ(Vector3f dest) {
+ dest.x = Math.atan2(-m21, m22);
+ dest.y = Math.atan2(m20, Math.sqrt(1.0f - m20 * m20));
+ dest.z = Math.atan2(-m10, m00);
+ return dest;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a
+ * 0 1 b
+ * 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @return this
+ */
+ public Matrix3f obliqueZ(float a, float b) {
+ this.m20 = m00 * a + m10 * b + m20;
+ this.m21 = m01 * a + m11 * b + m21;
+ this.m22 = m02 * a + m12 * b + m22;
+ return this;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a
+ * 0 1 b
+ * 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f obliqueZ(float a, float b, Matrix3f dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m00 * a + m10 * b + m20;
+ dest.m21 = m01 * a + m11 * b + m21;
+ dest.m22 = m02 * a + m12 * b + m22;
+ return dest;
+ }
+
+ public Matrix3f reflect(float nx, float ny, float nz, Matrix3f dest) {
+ float da = nx + nx, db = ny + ny, dc = nz + nz;
+ float rm00 = 1.0f - da * nx;
+ float rm01 = -da * ny;
+ float rm02 = -da * nz;
+ float rm10 = -db * nx;
+ float rm11 = 1.0f - db * ny;
+ float rm12 = -db * nz;
+ float rm20 = -dc * nx;
+ float rm21 = -dc * ny;
+ float rm22 = 1.0f - dc * nz;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ return dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @return this
+ */
+ public Matrix3f reflect(float nx, float ny, float nz) {
+ return reflect(nx, ny, nz, this);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @return this
+ */
+ public Matrix3f reflect(Vector3fc normal) {
+ return reflect(normal.x(), normal.y(), normal.z());
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @return this
+ */
+ public Matrix3f reflect(Quaternionfc orientation) {
+ return reflect(orientation, this);
+ }
+
+ public Matrix3f reflect(Quaternionfc orientation, Matrix3f dest) {
+ float num1 = orientation.x() + orientation.x();
+ float num2 = orientation.y() + orientation.y();
+ float num3 = orientation.z() + orientation.z();
+ float normalX = orientation.x() * num3 + orientation.w() * num2;
+ float normalY = orientation.y() * num3 - orientation.w() * num1;
+ float normalZ = 1.0f - (orientation.x() * num1 + orientation.y() * num2);
+ return reflect(normalX, normalY, normalZ, dest);
+ }
+
+ public Matrix3f reflect(Vector3fc normal, Matrix3f dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), dest);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @return this
+ */
+ public Matrix3f reflection(float nx, float ny, float nz) {
+ float da = nx + nx, db = ny + ny, dc = nz + nz;
+ this._m00(1.0f - da * nx);
+ this._m01(-da * ny);
+ this._m02(-da * nz);
+ this._m10(-db * nx);
+ this._m11(1.0f - db * ny);
+ this._m12(-db * nz);
+ this._m20(-dc * nx);
+ this._m21(-dc * ny);
+ this._m22(1.0f - dc * nz);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects through the given plane
+ * specified via the plane normal.
+ *
+ * @param normal
+ * the plane normal
+ * @return this
+ */
+ public Matrix3f reflection(Vector3fc normal) {
+ return reflection(normal.x(), normal.y(), normal.z());
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects through a plane
+ * specified via the plane orientation.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * @param orientation
+ * the plane orientation
+ * @return this
+ */
+ public Matrix3f reflection(Quaternionfc orientation) {
+ float num1 = orientation.x() + orientation.x();
+ float num2 = orientation.y() + orientation.y();
+ float num3 = orientation.z() + orientation.z();
+ float normalX = orientation.x() * num3 + orientation.w() * num2;
+ float normalY = orientation.y() * num3 - orientation.w() * num1;
+ float normalZ = 1.0f - (orientation.x() * num1 + orientation.y() * num2);
+ return reflection(normalX, normalY, normalZ);
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
+ Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
+ Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22);
+ }
+
+ public float quadraticFormProduct(float x, float y, float z) {
+ float Axx = m00 * x + m10 * y + m20 * z;
+ float Axy = m01 * x + m11 * y + m21 * z;
+ float Axz = m02 * x + m12 * y + m22 * z;
+ return x * Axx + y * Axy + z * Axz;
+ }
+
+ public float quadraticFormProduct(Vector3fc v) {
+ return quadraticFormProduct(v.x(), v.y(), v.z());
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapXZY() {
+ return mapXZY(this);
+ }
+ public Matrix3f mapXZY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapXZnY() {
+ return mapXZnY(this);
+ }
+ public Matrix3f mapXZnY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapXnYnZ() {
+ return mapXnYnZ(this);
+ }
+ public Matrix3f mapXnYnZ(Matrix3f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapXnZY() {
+ return mapXnZY(this);
+ }
+ public Matrix3f mapXnZY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapXnZnY() {
+ return mapXnZnY(this);
+ }
+ public Matrix3f mapXnZnY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYXZ() {
+ return mapYXZ(this);
+ }
+ public Matrix3f mapYXZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYXnZ() {
+ return mapYXnZ(this);
+ }
+ public Matrix3f mapYXnZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYZX() {
+ return mapYZX(this);
+ }
+ public Matrix3f mapYZX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYZnX() {
+ return mapYZnX(this);
+ }
+ public Matrix3f mapYZnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYnXZ() {
+ return mapYnXZ(this);
+ }
+ public Matrix3f mapYnXZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYnXnZ() {
+ return mapYnXnZ(this);
+ }
+ public Matrix3f mapYnXnZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYnZX() {
+ return mapYnZX(this);
+ }
+ public Matrix3f mapYnZX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapYnZnX() {
+ return mapYnZnX(this);
+ }
+ public Matrix3f mapYnZnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZXY() {
+ return mapZXY(this);
+ }
+ public Matrix3f mapZXY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZXnY() {
+ return mapZXnY(this);
+ }
+ public Matrix3f mapZXnY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZYX() {
+ return mapZYX(this);
+ }
+ public Matrix3f mapZYX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZYnX() {
+ return mapZYnX(this);
+ }
+ public Matrix3f mapZYnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZnXY() {
+ return mapZnXY(this);
+ }
+ public Matrix3f mapZnXY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZnXnY() {
+ return mapZnXnY(this);
+ }
+ public Matrix3f mapZnXnY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZnYX() {
+ return mapZnYX(this);
+ }
+ public Matrix3f mapZnYX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapZnYnX() {
+ return mapZnYnX(this);
+ }
+ public Matrix3f mapZnYnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXYnZ() {
+ return mapnXYnZ(this);
+ }
+ public Matrix3f mapnXYnZ(Matrix3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXZY() {
+ return mapnXZY(this);
+ }
+ public Matrix3f mapnXZY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXZnY() {
+ return mapnXZnY(this);
+ }
+ public Matrix3f mapnXZnY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXnYZ() {
+ return mapnXnYZ(this);
+ }
+ public Matrix3f mapnXnYZ(Matrix3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXnYnZ() {
+ return mapnXnYnZ(this);
+ }
+ public Matrix3f mapnXnYnZ(Matrix3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXnZY() {
+ return mapnXnZY(this);
+ }
+ public Matrix3f mapnXnZY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnXnZnY() {
+ return mapnXnZnY(this);
+ }
+ public Matrix3f mapnXnZnY(Matrix3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYXZ() {
+ return mapnYXZ(this);
+ }
+ public Matrix3f mapnYXZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYXnZ() {
+ return mapnYXnZ(this);
+ }
+ public Matrix3f mapnYXnZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYZX() {
+ return mapnYZX(this);
+ }
+ public Matrix3f mapnYZX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYZnX() {
+ return mapnYZnX(this);
+ }
+ public Matrix3f mapnYZnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYnXZ() {
+ return mapnYnXZ(this);
+ }
+ public Matrix3f mapnYnXZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYnXnZ() {
+ return mapnYnXnZ(this);
+ }
+ public Matrix3f mapnYnXnZ(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYnZX() {
+ return mapnYnZX(this);
+ }
+ public Matrix3f mapnYnZX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnYnZnX() {
+ return mapnYnZnX(this);
+ }
+ public Matrix3f mapnYnZnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZXY() {
+ return mapnZXY(this);
+ }
+ public Matrix3f mapnZXY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZXnY() {
+ return mapnZXnY(this);
+ }
+ public Matrix3f mapnZXnY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZYX() {
+ return mapnZYX(this);
+ }
+ public Matrix3f mapnZYX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZYnX() {
+ return mapnZYnX(this);
+ }
+ public Matrix3f mapnZYnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZnXY() {
+ return mapnZnXY(this);
+ }
+ public Matrix3f mapnZnXY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZnXnY() {
+ return mapnZnXnY(this);
+ }
+ public Matrix3f mapnZnXnY(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZnYX() {
+ return mapnZnYX(this);
+ }
+ public Matrix3f mapnZnYX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix3f mapnZnYnX() {
+ return mapnZnYnX(this);
+ }
+ public Matrix3f mapnZnYnX(Matrix3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f negateX() {
+ return _m00(-m00)._m01(-m01)._m02(-m02);
+ }
+ public Matrix3f negateX(Matrix3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(m20)._m21(m21)._m22(m22);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f negateY() {
+ return _m10(-m10)._m11(-m11)._m12(-m12);
+ }
+ public Matrix3f negateY(Matrix3f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ *
+ * @return this
+ */
+ public Matrix3f negateZ() {
+ return _m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ public Matrix3f negateZ(Matrix3f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3fStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3fStack.java
new file mode 100644
index 000000000..8e53a5456
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3fStack.java
@@ -0,0 +1,186 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2018-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix3f} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix3fStack} class inherits from {@link Matrix3f}, so the current/top matrix is always the
+ * {@link Matrix3fStack}/{@link Matrix3f} itself. This affects all operations in {@link Matrix3f} that take another
+ * {@link Matrix3f} as parameter. If a {@link Matrix3fStack} is used as argument to those methods, the effective
+ * argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix3fStack extends Matrix3f {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix3fStack(int) constructor}.
+ */
+ private Matrix3f[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix3fStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix3fStack} simply only consists of this
+ * {@link Matrix3f}
+ */
+ public Matrix3fStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix3f[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix3f();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix3fStack} instance.
+ */
+ public Matrix3fStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix3fStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix3fStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix3fStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix3f and Matrix3fStack:
+ *
+ * - Matrix3f.equals(Matrix3fStack) is true iff all the 9 matrix elements are equal
+ * - Matrix3fStack.equals(Matrix3f) is true iff all the 9 matrix elements are equal
+ * - Matrix3fStack.equals(Matrix3fStack) is true iff all 9 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix3fStack) {
+ Matrix3fStack other = (Matrix3fStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix3fStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix3f m = new Matrix3f();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix3fStack cloned = (Matrix3fStack) super.clone();
+ Matrix3f[] clonedMats = new Matrix3f[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix3f) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3fc.java
new file mode 100644
index 000000000..9ffaf1905
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3fc.java
@@ -0,0 +1,2199 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+
+/**
+ * Interface to a read-only view of a 3x3 matrix of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix3fc {
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m01();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m02();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m11();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m12();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m21();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m22();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mul(Matrix3fc right, Matrix3f dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix3f mulLocal(Matrix3fc left, Matrix3f dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ float determinant();
+
+ /**
+ * Invert the this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f invert(Matrix3f dest);
+
+ /**
+ * Transpose this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f transpose(Matrix3f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3f get(Matrix3f dest);
+
+ /**
+ * Get the current values of this
matrix and store them as
+ * the rotational component of dest
. All other values of dest
will
+ * be set to identity.
+ *
+ * @see Matrix4f#set(Matrix3fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4f get(Matrix4f dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link AxisAngle4f}.
+ *
+ * @see AxisAngle4f#set(Matrix3fc)
+ *
+ * @param dest
+ * the destination {@link AxisAngle4f}
+ * @return the passed in destination
+ */
+ AxisAngle4f getRotation(AxisAngle4f dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the three column vectors of this matrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaternionf#setFromUnnormalized(Matrix3fc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getUnnormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the three column vectors of this matrix are normalized.
+ *
+ * @see Quaternionf#setFromNormalized(Matrix3fc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getNormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the three column vectors of this matrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaterniond#setFromUnnormalized(Matrix3fc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getUnnormalizedRotation(Quaterniond dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the three column vectors of this matrix are normalized.
+ *
+ * @see Quaterniond#setFromNormalized(Matrix3fc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getNormalizedRotation(Quaterniond dest);
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix as 3x4 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get3x4(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x4(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this 3x3 matrix as 3x4 matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x4(FloatBuffer buffer);
+
+ /**
+ * Store this matrix as 3x4 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this 3x3 matrix as 3x4 matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x4(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix as 3x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this 3x3 matrix as 3x4 matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x4(ByteBuffer buffer);
+
+ /**
+ * Store this matrix as 3x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this 3x3 matrix as 3x4 matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(FloatBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(int index, FloatBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix3fc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f scale(Vector3fc xyz, Matrix3f dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f scale(float x, float y, float z, Matrix3f dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(float, float, float, Matrix3f)
+ *
+ * @param xyz
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f scale(float xyz, Matrix3f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f scaleLocal(float x, float y, float z, Matrix3f dest);
+
+ /**
+ * Transform the given vector by this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector3f transform(Vector3f v);
+
+ /**
+ * Transform the given vector by this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform the vector (x, y, z)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform the given vector by the transpose of this matrix.
+ *
+ * @param v
+ * the vector to transform
+ * @return v
+ */
+ Vector3f transformTranspose(Vector3f v);
+
+ /**
+ * Transform the given vector by the transpose of this matrix and store the result in dest
.
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformTranspose(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform the vector (x, y, z)
by the transpose of this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformTranspose(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateX(float ang, Matrix3f dest);
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateY(float ang, Matrix3f dest);
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateZ(float ang, Matrix3f dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateXYZ(float angleX, float angleY, float angleZ, Matrix3f dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateZYX(float angleZ, float angleY, float angleX, Matrix3f dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateYXZ(float angleY, float angleX, float angleZ, Matrix3f dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components, and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotate(float ang, float x, float y, float z, Matrix3f dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateLocal(float ang, float x, float y, float z, Matrix3f dest);
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateLocalX(float ang, Matrix3f dest);
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateLocalY(float ang, Matrix3f dest);
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateLocalZ(float ang, Matrix3f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotate(Quaternionfc quat, Matrix3f dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateLocal(Quaternionfc quat, Matrix3f dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float, Matrix3f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotate(AxisAngle4f axisAngle, Matrix3f dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float, Matrix3f)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotate(float angle, Vector3fc axis, Matrix3f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * @see #lookAlong(float, float, float, float, float, float, Matrix3f)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f lookAlong(Vector3fc dir, Vector3fc up, Matrix3f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix3f dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ Vector3f getRow(int row, Vector3f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the matrix element value at the given column and row.
+ *
+ * @param column
+ * the colum index in [0..2]
+ * @param row
+ * the row index in [0..2]
+ * @return the element value
+ */
+ float get(int column, int row);
+
+ /**
+ * Get the matrix element value at the given row and column.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param column
+ * the colum index in [0..2]
+ * @return the element value
+ */
+ float getRowColumn(int row, int column);
+
+ /**
+ * Compute a normal matrix from this
matrix and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f normal(Matrix3f dest);
+
+ /**
+ * Compute the cofactor matrix of this
and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f cofactor(Matrix3f dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
, y
and z
+ * @return dest
+ */
+ Vector3f getScale(Vector3f dest);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3f inv = new Matrix3f(this).invert();
+ * inv.transform(dir.set(0, 0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveZ(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f positiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3f inv = new Matrix3f(this).transpose();
+ * inv.transform(dir.set(0, 0, 1));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f normalizedPositiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3f inv = new Matrix3f(this).invert();
+ * inv.transform(dir.set(1, 0, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f positiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3f inv = new Matrix3f(this).transpose();
+ * inv.transform(dir.set(1, 0, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f normalizedPositiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3f inv = new Matrix3f(this).invert();
+ * inv.transform(dir.set(0, 1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f positiveY(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3f inv = new Matrix3f(this).transpose();
+ * inv.transform(dir.set(0, 1, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f normalizedPositiveY(Vector3f dir);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f add(Matrix3fc other, Matrix3f dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f sub(Matrix3fc subtrahend, Matrix3f dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mulComponentWise(Matrix3fc other, Matrix3f dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f lerp(Matrix3fc other, float t, Matrix3f dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix3f().lookAlong(new Vector3f(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(float, float, float, float, float, float, Matrix3f)
+ *
+ * @param direction
+ * the direction to rotate towards
+ * @param up
+ * the model's up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateTowards(Vector3fc direction, Vector3fc up, Matrix3f dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix3f().lookAlong(-dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc, Matrix3f)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix3f dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by this
matrix and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that this
matrix only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order X * Y * Z
to obtain the identical matrix.
+ * This means that calling {@link Matrix3fc#rotateXYZ(float, float, float, Matrix3f)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix3f m = ...; // <- matrix only representing rotation
+ * Matrix3f n = new Matrix3f();
+ * n.rotateXYZ(m.getEulerAnglesXYZ(new Vector3f()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3f getEulerAnglesXYZ(Vector3f dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by this
matrix and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that this
matrix only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order Z * Y * X
to obtain the identical matrix.
+ * This means that calling {@link Matrix3fc#rotateZYX(float, float, float, Matrix3f)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix3f m = ...; // <- matrix only representing rotation
+ * Matrix3f n = new Matrix3f();
+ * n.rotateZYX(m.getEulerAnglesZYX(new Vector3f()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3f getEulerAnglesZYX(Vector3f dest);
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a
+ * 0 1 b
+ * 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f obliqueZ(float a, float b, Matrix3f dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix3fc m, float delta);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal (nx, ny, nz)
, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3f reflect(float nx, float ny, float nz, Matrix3f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through a plane
+ * specified via the plane orientation, and store the result in dest
.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3f reflect(Quaternionfc orientation, Matrix3f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects through the given plane
+ * specified via the plane normal, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3f reflect(Vector3fc normal, Matrix3f dest);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compute (x, y, z)^T * this * (x, y, z)
.
+ *
+ * @param x
+ * the x coordinate of the vector to multiply
+ * @param y
+ * the y coordinate of the vector to multiply
+ * @param z
+ * the z coordinate of the vector to multiply
+ * @return the result
+ */
+ float quadraticFormProduct(float x, float y, float z);
+
+ /**
+ * Compute v^T * this * v
.
+ *
+ * @param v
+ * the vector to multiply
+ * @return the result
+ */
+ float quadraticFormProduct(Vector3fc v);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapXZY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapXZnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapXnYnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapXnZY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapXnZnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYXZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYXnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYZX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYZnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYnXZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYnXnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYnZX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapYnZnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZXY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZXnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZYX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZYnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZnXY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZnXnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZnYX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapZnYnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXYnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXZY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXZnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXnYZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 -1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXnYnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXnZY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 0 -1
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnXnZnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYXZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYXnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYZX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYZnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYnXZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * -1 0 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYnXnZ(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * -1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYnZX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * -1 0 0
+ * 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnYnZnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZXY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZXnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZYX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZYnX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZnXY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0
+ * 0 0 -1
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZnXnY(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1
+ * 0 -1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZnYX(Matrix3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1
+ * 0 -1 0
+ * -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f mapnZnYnX(Matrix3f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0
+ * 0 1 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f negateX(Matrix3f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 -1 0
+ * 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f negateY(Matrix3f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0
+ * 0 1 0
+ * 0 0 -1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f negateZ(Matrix3f dest);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2d.java
new file mode 100644
index 000000000..527084c25
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2d.java
@@ -0,0 +1,2497 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2017-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+
+/**
+ * Contains the definition of a 3x2 matrix of doubles, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20
+ * m01 m11 m21
+ *
+ * @author Kai Burjack
+ */
+public class Matrix3x2d implements Matrix3x2dc, Cloneable, Externalizable {
+
+ private static final long serialVersionUID = 1L;
+
+ public double m00, m01;
+ public double m10, m11;
+ public double m20, m21;
+
+ /**
+ * Create a new {@link Matrix3x2d} and set it to {@link #identity() identity}.
+ */
+ public Matrix3x2d() {
+ this.m00 = 1.0;
+ this.m11 = 1.0;
+ }
+
+ /**
+ * Create a new {@link Matrix3x2d} by setting its left 2x2 submatrix to the values of the given {@link Matrix2dc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix2dc}
+ */
+ public Matrix3x2d(Matrix2dc mat) {
+ if (mat instanceof Matrix2d) {
+ MemUtil.INSTANCE.copy((Matrix2d) mat, this);
+ } else {
+ setMatrix2dc(mat);
+ }
+ }
+
+ /**
+ * Create a new {@link Matrix3x2d} by setting its left 2x2 submatrix to the values of the given {@link Matrix2fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix2fc}
+ */
+ public Matrix3x2d(Matrix2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Create a new {@link Matrix3x2d} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix3x2dc} to copy the values from
+ */
+ public Matrix3x2d(Matrix3x2dc mat) {
+ if (mat instanceof Matrix3x2d) {
+ MemUtil.INSTANCE.copy((Matrix3x2d) mat, this);
+ } else {
+ setMatrix3x2dc(mat);
+ }
+ }
+
+ /**
+ * Create a new 3x2 matrix using the supplied double values. The order of the parameter is column-major,
+ * so the first two parameters specify the two elements of the first column.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ */
+ public Matrix3x2d(double m00, double m01,
+ double m10, double m11,
+ double m20, double m21) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m20 = m20;
+ this.m21 = m21;
+ }
+
+ /**
+ * Create a new {@link Matrix3x2d} by reading its 6 double components from the given {@link DoubleBuffer}
+ * at the buffer's current position.
+ *
+ * That DoubleBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link DoubleBuffer} to read the matrix values from
+ */
+ public Matrix3x2d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ public double m00() {
+ return m00;
+ }
+ public double m01() {
+ return m01;
+ }
+ public double m10() {
+ return m10;
+ }
+ public double m11() {
+ return m11;
+ }
+ public double m20() {
+ return m20;
+ }
+ public double m21() {
+ return m21;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix3x2d _m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix3x2d _m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix3x2d _m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix3x2d _m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix3x2d _m20(double m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix3x2d _m21(double m21) {
+ this.m21 = m21;
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the ones in m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix3x2d set(Matrix3x2dc m) {
+ if (m instanceof Matrix3x2d) {
+ MemUtil.INSTANCE.copy((Matrix3x2d) m, this);
+ } else {
+ setMatrix3x2dc(m);
+ }
+ return this;
+ }
+ private void setMatrix3x2dc(Matrix3x2dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ }
+
+ /**
+ * Set the left 2x2 submatrix of this {@link Matrix3x2d} to the given {@link Matrix2dc} and don't change the other elements.
+ *
+ * @param m
+ * the 2x2 matrix
+ * @return this
+ */
+ public Matrix3x2d set(Matrix2dc m) {
+ if (m instanceof Matrix2d) {
+ MemUtil.INSTANCE.copy((Matrix2d) m, this);
+ } else {
+ setMatrix2dc(m);
+ }
+ return this;
+ }
+ private void setMatrix2dc(Matrix2dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Set the left 2x2 submatrix of this {@link Matrix3x2d} to the given {@link Matrix2fc} and don't change the other elements.
+ *
+ * @param m
+ * the 2x2 matrix
+ * @return this
+ */
+ public Matrix3x2d set(Matrix2fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m10 = m.m10();
+ m11 = m.m11();
+ return this;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix by assuming a third row in
+ * both matrices of (0, 0, 1)
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3x2d mul(Matrix3x2dc right) {
+ return mul(right, this);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix by assuming a third row in
+ * both matrices of (0, 0, 1)
and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d mul(Matrix3x2dc right, Matrix3x2d dest) {
+ double nm00 = m00 * right.m00() + m10 * right.m01();
+ double nm01 = m01 * right.m00() + m11 * right.m01();
+ double nm10 = m00 * right.m10() + m10 * right.m11();
+ double nm11 = m01 * right.m10() + m11 * right.m11();
+ double nm20 = m00 * right.m20() + m10 * right.m21() + m20;
+ double nm21 = m01 * right.m20() + m11 * right.m21() + m21;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3x2d mulLocal(Matrix3x2dc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix3x2d mulLocal(Matrix3x2dc left, Matrix3x2d dest) {
+ double nm00 = left.m00() * m00 + left.m10() * m01;
+ double nm01 = left.m01() * m00 + left.m11() * m01;
+ double nm10 = left.m00() * m10 + left.m10() * m11;
+ double nm11 = left.m01() * m10 + left.m11() * m11;
+ double nm20 = left.m00() * m20 + left.m10() * m21 + left.m20();
+ double nm21 = left.m01() * m20 + left.m11() * m21 + left.m21();
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied double values. The result looks like this:
+ *
+ * m00, m10, m20
+ * m01, m11, m21
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @return this
+ */
+ public Matrix3x2d set(double m00, double m01,
+ double m10, double m11,
+ double m20, double m21) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m20 = m20;
+ this.m21 = m21;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied double array. The result looks like this:
+ *
+ * 0, 2, 4
+ * 1, 3, 5
+ *
+ * This method only uses the first 6 values, all others are ignored.
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix3x2d set(double m[]) {
+ MemUtil.INSTANCE.copy(m, 0, this);
+ return this;
+ }
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ public double determinant() {
+ return m00 * m11 - m01 * m10;
+ }
+
+ /**
+ * Invert this matrix by assuming a third row in this matrix of (0, 0, 1)
.
+ *
+ * @return this
+ */
+ public Matrix3x2d invert() {
+ return invert(this);
+ }
+
+ /**
+ * Invert the this
matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d invert(Matrix3x2d dest) {
+ // client must make sure that matrix is invertible
+ double s = 1.0 / (m00 * m11 - m01 * m10);
+ double nm00 = m11 * s;
+ double nm01 = -m01 * s;
+ double nm10 = -m10 * s;
+ double nm11 = m00 * s;
+ double nm20 = (m10 * m21 - m20 * m11) * s;
+ double nm21 = (m20 * m01 - m00 * m21) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix in a two-dimensional coordinate system.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to apply a translation via to an already existing transformation
+ * matrix, use {@link #translate(double, double) translate()} instead.
+ *
+ * @see #translate(double, double)
+ *
+ * @param x
+ * the units to translate in x
+ * @param y
+ * the units to translate in y
+ * @return this
+ */
+ public Matrix3x2d translation(double x, double y) {
+ m00 = 1.0;
+ m01 = 0.0;
+ m10 = 0.0;
+ m11 = 1.0;
+ m20 = x;
+ m21 = y;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix in a two-dimensional coordinate system.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to apply a translation via to an already existing transformation
+ * matrix, use {@link #translate(Vector2dc) translate()} instead.
+ *
+ * @see #translate(Vector2dc)
+ *
+ * @param offset
+ * the translation
+ * @return this
+ */
+ public Matrix3x2d translation(Vector2dc offset) {
+ return translation(offset.x(), offset.y());
+ }
+
+ /**
+ * Set only the translation components of this matrix (m20, m21)
to the given values (x, y)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(double, double)}.
+ * To apply a translation to another matrix, use {@link #translate(double, double)}.
+ *
+ * @see #translation(double, double)
+ * @see #translate(double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @return this
+ */
+ public Matrix3x2d setTranslation(double x, double y) {
+ m20 = x;
+ m21 = y;
+ return this;
+ }
+
+ /**
+ * Set only the translation components of this matrix (m20, m21)
to the given values (offset.x, offset.y)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(Vector2dc)}.
+ * To apply a translation to another matrix, use {@link #translate(Vector2dc)}.
+ *
+ * @see #translation(Vector2dc)
+ * @see #translate(Vector2dc)
+ *
+ * @param offset
+ * the new translation to set
+ * @return this
+ */
+ public Matrix3x2d setTranslation(Vector2dc offset) {
+ return setTranslation(offset.x(), offset.y());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y and store the result
+ * in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(double, double)}.
+ *
+ * @see #translation(double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d translate(double x, double y, Matrix3x2d dest) {
+ double rm20 = x;
+ double rm21 = y;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ return dest;
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(double, double)}.
+ *
+ * @see #translation(double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @return this
+ */
+ public Matrix3x2d translate(double x, double y) {
+ return translate(x, y, this);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y, and
+ * store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector2dc)}.
+ *
+ * @see #translation(Vector2dc)
+ *
+ * @param offset
+ * the offset to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d translate(Vector2dc offset, Matrix3x2d dest) {
+ return translate(offset.x(), offset.y(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector2dc)}.
+ *
+ * @see #translation(Vector2dc)
+ *
+ * @param offset
+ * the offset to translate
+ * @return this
+ */
+ public Matrix3x2d translate(Vector2dc offset) {
+ return translate(offset.x(), offset.y(), this);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector2dc)}.
+ *
+ * @see #translation(Vector2dc)
+ *
+ * @param offset
+ * the number of units in x and y by which to translate
+ * @return this
+ */
+ public Matrix3x2d translateLocal(Vector2dc offset) {
+ return translateLocal(offset.x(), offset.y());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector2dc)}.
+ *
+ * @see #translation(Vector2dc)
+ *
+ * @param offset
+ * the number of units in x and y by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d translateLocal(Vector2dc offset, Matrix3x2d dest) {
+ return translateLocal(offset.x(), offset.y(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(double, double)}.
+ *
+ * @see #translation(double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d translateLocal(double x, double y, Matrix3x2d dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m20 = m20 + x;
+ dest.m21 = m21 + y;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(double, double)}.
+ *
+ * @see #translation(double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @return this
+ */
+ public Matrix3x2d translateLocal(double x, double y) {
+ return translateLocal(x, y, this);
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix3x2dc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix3x2dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ public Matrix3x2d get(Matrix3x2d dest) {
+ return dest.set(this);
+ }
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public DoubleBuffer get3x3(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public DoubleBuffer get3x3(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public ByteBuffer get3x3(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public ByteBuffer get3x3(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public DoubleBuffer get4x4(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public DoubleBuffer get4x4(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public ByteBuffer get4x4(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public ByteBuffer get4x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ public Matrix3x2dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Store this matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ public double[] get(double[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ /**
+ * Store this matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(double[], int)}.
+ *
+ * @see #get(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ public double[] get(double[] arr) {
+ return get(arr, 0);
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied float array at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ public double[] get3x3(double[] arr, int offset) {
+ MemUtil.INSTANCE.copy3x3(this, arr, offset);
+ return arr;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get3x3(double[], int)}.
+ *
+ * @see #get3x3(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ public double[] get3x3(double[] arr) {
+ return get3x3(arr, 0);
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied float array at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ public double[] get4x4(double[] arr, int offset) {
+ MemUtil.INSTANCE.copy4x4(this, arr, offset);
+ return arr;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(double[], int)}.
+ *
+ * @see #get4x4(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ public double[] get4x4(double[] arr) {
+ return get4x4(arr, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2d set(DoubleBuffer buffer) {
+ int pos = buffer.position();
+ MemUtil.INSTANCE.get(this, pos, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2d set(ByteBuffer buffer) {
+ int pos = buffer.position();
+ MemUtil.INSTANCE.get(this, pos, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+ /**
+ * Set the values of this matrix by reading 6 double values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set all values within this matrix to zero.
+ *
+ * @return this
+ */
+ public Matrix3x2d zero() {
+ MemUtil.INSTANCE.zero(this);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the identity.
+ *
+ * @return this
+ */
+ public Matrix3x2d identity() {
+ MemUtil.INSTANCE.identity(this);
+ return this;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the unit axes by the given x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d scale(double x, double y, Matrix3x2d dest) {
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x and y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix3x2d scale(double x, double y) {
+ return scale(x, y, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @return this
+ */
+ public Matrix3x2d scale(Vector2dc xy) {
+ return scale(xy.x(), xy.y(), this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d scale(Vector2dc xy, Matrix3x2d dest) {
+ return scale(xy.x(), xy.y(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @return this
+ */
+ public Matrix3x2d scale(Vector2fc xy) {
+ return scale(xy.x(), xy.y(), this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d scale(Vector2fc xy, Matrix3x2d dest) {
+ return scale(xy.x(), xy.y(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling the two base axes by the given xy
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @see #scale(double, double, Matrix3x2d)
+ *
+ * @param xy
+ * the factor for the two components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d scale(double xy, Matrix3x2d dest) {
+ return scale(xy, xy, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling the two base axes by the given xyz
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @see #scale(double, double)
+ *
+ * @param xy
+ * the factor for the two components
+ * @return this
+ */
+ public Matrix3x2d scale(double xy) {
+ return scale(xy, xy);
+ }
+
+ public Matrix3x2d scaleLocal(double x, double y, Matrix3x2d dest) {
+ dest.m00 = x * m00;
+ dest.m01 = y * m01;
+ dest.m10 = x * m10;
+ dest.m11 = y * m11;
+ dest.m20 = x * m20;
+ dest.m21 = y * m21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x and y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix3x2d scaleLocal(double x, double y) {
+ return scaleLocal(x, y, this);
+ }
+
+ public Matrix3x2d scaleLocal(double xy, Matrix3x2d dest) {
+ return scaleLocal(xy, xy, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given xy factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param xy
+ * the factor of the x and y component
+ * @return this
+ */
+ public Matrix3x2d scaleLocal(double xy) {
+ return scaleLocal(xy, xy, this);
+ }
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin, and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(sx, sy).translate(-ox, -oy)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d scaleAround(double sx, double sy, double ox, double oy, Matrix3x2d dest) {
+ double nm20 = m00 * ox + m10 * oy + m20;
+ double nm21 = m01 * ox + m11 * oy + m21;
+ dest.m00 = m00 * sx;
+ dest.m01 = m01 * sx;
+ dest.m10 = m10 * sy;
+ dest.m11 = m11 * sy;
+ dest.m20 = dest.m00 * -ox + dest.m10 * -oy + nm20;
+ dest.m21 = dest.m01 * -ox + dest.m11 * -oy + nm21;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy).scale(sx, sy).translate(-ox, -oy)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2d scaleAround(double sx, double sy, double ox, double oy) {
+ return scaleAround(sx, sy, ox, oy, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(factor).translate(-ox, -oy)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ public Matrix3x2d scaleAround(double factor, double ox, double oy, Matrix3x2d dest) {
+ return scaleAround(factor, factor, ox, oy, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy).scale(factor).translate(-ox, -oy)
+ *
+ * @param factor
+ * the scaling factor for all axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2d scaleAround(double factor, double ox, double oy) {
+ return scaleAround(factor, factor, ox, oy, this);
+ }
+
+ public Matrix3x2d scaleAroundLocal(double sx, double sy, double ox, double oy, Matrix3x2d dest) {
+ dest.m00 = sx * m00;
+ dest.m01 = sy * m01;
+ dest.m10 = sx * m10;
+ dest.m11 = sy * m11;
+ dest.m20 = sx * m20 - sx * ox + ox;
+ dest.m21 = sy * m21 - sy * oy + oy;
+ return dest;
+ }
+
+ public Matrix3x2d scaleAroundLocal(double factor, double ox, double oy, Matrix3x2d dest) {
+ return scaleAroundLocal(factor, factor, ox, oy, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2d().translate(ox, oy).scale(sx, sy).translate(-ox, -oy).mul(this, this)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz) {
+ return scaleAroundLocal(sx, sy, ox, oy, this);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2d().translate(ox, oy).scale(factor).translate(-ox, -oy).mul(this, this)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2d scaleAroundLocal(double factor, double ox, double oy) {
+ return scaleAroundLocal(factor, factor, ox, oy, this);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales the two base axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a matrix, use {@link #scale(double) scale()} instead.
+ *
+ * @see #scale(double)
+ *
+ * @param factor
+ * the scale factor in x and y
+ * @return this
+ */
+ public Matrix3x2d scaling(double factor) {
+ return scaling(factor, factor);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @return this
+ */
+ public Matrix3x2d scaling(double x, double y) {
+ m00 = x;
+ m01 = 0.0;
+ m10 = 0.0;
+ m11 = y;
+ m20 = 0.0;
+ m21 = 0.0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(double) rotate()} instead.
+ *
+ * @see #rotate(double)
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3x2d rotation(double angle) {
+ double cos = Math.cos(angle);
+ double sin = Math.sin(angle);
+ m00 = cos;
+ m10 = -sin;
+ m20 = 0.0;
+ m01 = sin;
+ m11 = cos;
+ m21 = 0.0;
+ return this;
+ }
+
+ /**
+ * Transform/multiply the given vector by this matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in that vector.
+ *
+ * @see Vector3d#mul(Matrix3x2dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ public Vector3d transform(Vector3d v) {
+ return v.mul(this);
+ }
+
+ /**
+ * Transform/multiply the given vector by this matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in dest
.
+ *
+ * @see Vector3d#mul(Matrix3x2dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ public Vector3d transform(Vector3dc v, Vector3d dest) {
+ return v.mul(this, dest);
+ }
+
+ /**
+ * Transform/multiply the given vector (x, y, z)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param z
+ * the z component of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ public Vector3d transform(double x, double y, double z, Vector3d dest) {
+ return dest.set(m00 * x + m10 * y + m20 * z, m01 * x + m11 * y + m21 * z, z);
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector2dc, Vector2d)}.
+ *
+ * @see #transformPosition(Vector2dc, Vector2d)
+ * @see #transform(Vector3d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ public Vector2d transformPosition(Vector2d v) {
+ v.set(m00 * v.x + m10 * v.y + m20,
+ m01 * v.x + m11 * v.y + m21);
+ return v;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2d)}.
+ *
+ * @see #transformPosition(Vector2d)
+ * @see #transform(Vector3dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2d transformPosition(Vector2dc v, Vector2d dest) {
+ dest.set(m00 * v.x() + m10 * v.y() + m20,
+ m01 * v.x() + m11 * v.y() + m21);
+ return dest;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2d)}.
+ *
+ * @see #transformPosition(Vector2d)
+ * @see #transform(Vector3dc, Vector3d)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2d transformPosition(double x, double y, Vector2d dest) {
+ return dest.set(m00 * x + m10 * y + m20, m01 * x + m11 * y + m21);
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector2dc, Vector2d)}.
+ *
+ * @see #transformDirection(Vector2dc, Vector2d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ public Vector2d transformDirection(Vector2d v) {
+ v.set(m00 * v.x + m10 * v.y,
+ m01 * v.x + m11 * v.y);
+ return v;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2d)}.
+ *
+ * @see #transformDirection(Vector2d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2d transformDirection(Vector2dc v, Vector2d dest) {
+ dest.set(m00 * v.x() + m10 * v.y(),
+ m01 * v.x() + m11 * v.y());
+ return dest;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2d)}.
+ *
+ * @see #transformDirection(Vector2d)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2d transformDirection(double x, double y, Vector2d dest) {
+ return dest.set(m00 * x + m10 * y, m01 * x + m11 * y);
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(m00);
+ out.writeDouble(m01);
+ out.writeDouble(m10);
+ out.writeDouble(m11);
+ out.writeDouble(m20);
+ out.writeDouble(m21);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readDouble();
+ m01 = in.readDouble();
+ m10 = in.readDouble();
+ m11 = in.readDouble();
+ m20 = in.readDouble();
+ m21 = in.readDouble();
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3x2d rotate(double ang) {
+ return rotate(ang, this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d rotate(double ang, Matrix3x2d dest) {
+ double cos = Math.cos(ang);
+ double sin = Math.sin(ang);
+ double rm00 = cos;
+ double rm01 = sin;
+ double rm10 = -sin;
+ double rm11 = cos;
+ double nm00 = m00 * rm00 + m10 * rm01;
+ double nm01 = m01 * rm00 + m11 * rm01;
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double)
+ *
+ * @param ang
+ * the angle in radians to rotate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d rotateLocal(double ang, Matrix3x2d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm00 = cos * m00 - sin * m01;
+ double nm01 = sin * m00 + cos * m01;
+ double nm10 = cos * m10 - sin * m11;
+ double nm11 = sin * m10 + cos * m11;
+ double nm20 = cos * m20 - sin * m21;
+ double nm21 = sin * m20 + cos * m21;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double)
+ *
+ * @param ang
+ * the angle in radians to rotate
+ * @return this
+ */
+ public Matrix3x2d rotateLocal(double ang) {
+ return rotateLocal(ang, this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians about
+ * the specified rotation center (x, y)
.
+ *
+ * This method is equivalent to calling: translate(x, y).rotate(ang).translate(-x, -y)
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @see #translate(double, double)
+ * @see #rotate(double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the rotation center
+ * @param y
+ * the y component of the rotation center
+ * @return this
+ */
+ public Matrix3x2d rotateAbout(double ang, double x, double y) {
+ return rotateAbout(ang, x, y, this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians about
+ * the specified rotation center (x, y)
and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(x, y, dest).rotate(ang).translate(-x, -y)
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @see #translate(double, double, Matrix3x2d)
+ * @see #rotate(double, Matrix3x2d)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the rotation center
+ * @param y
+ * the y component of the rotation center
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d rotateAbout(double ang, double x, double y, Matrix3x2d dest) {
+ double tm20 = m00 * x + m10 * y + m20;
+ double tm21 = m01 * x + m11 * y + m21;
+ double cos = Math.cos(ang);
+ double sin = Math.sin(ang);
+ double nm00 = m00 * cos + m10 * sin;
+ double nm01 = m01 * cos + m11 * sin;
+ dest.m10 = m00 * -sin + m10 * cos;
+ dest.m11 = m01 * -sin + m11 * cos;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m20 = dest.m00 * -x + dest.m10 * -y + tm20;
+ dest.m21 = dest.m01 * -x + dest.m11 * -y + tm21;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix that rotates the given normalized fromDir
direction vector
+ * to point along the normalized toDir
, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param fromDir
+ * the normalized direction which should be rotate to point along toDir
+ * @param toDir
+ * the normalized destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d rotateTo(Vector2dc fromDir, Vector2dc toDir, Matrix3x2d dest) {
+ double dot = fromDir.x() * toDir.x() + fromDir.y() * toDir.y();
+ double det = fromDir.x() * toDir.y() - fromDir.y() * toDir.x();
+ double rm00 = dot;
+ double rm01 = det;
+ double rm10 = -det;
+ double rm11 = dot;
+ double nm00 = m00 * rm00 + m10 * rm01;
+ double nm01 = m01 * rm00 + m11 * rm01;
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix that rotates the given normalized fromDir
direction vector
+ * to point along the normalized toDir
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param fromDir
+ * the normalized direction which should be rotate to point along toDir
+ * @param toDir
+ * the normalized destination direction
+ * @return this
+ */
+ public Matrix3x2d rotateTo(Vector2dc fromDir, Vector2dc toDir) {
+ return rotateTo(fromDir, toDir, this);
+ }
+
+ /**
+ * Apply a "view" transformation to this matrix that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * @see #setView(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2d view(double left, double right, double bottom, double top, Matrix3x2d dest) {
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm20 = (left + right) / (left - right);
+ double rm21 = (bottom + top) / (bottom - top);
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ return dest;
+ }
+
+ /**
+ * Apply a "view" transformation to this matrix that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * @see #setView(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @return this
+ */
+ public Matrix3x2d view(double left, double right, double bottom, double top) {
+ return view(left, right, bottom, top, this);
+ }
+
+ /**
+ * Set this matrix to define a "view" transformation that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively.
+ *
+ * @see #view(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @return this
+ */
+ public Matrix3x2d setView(double left, double right, double bottom, double top) {
+ m00 = 2.0 / (right - left);
+ m01 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / (top - bottom);
+ m20 = (left + right) / (left - right);
+ m21 = (bottom + top) / (bottom - top);
+ return this;
+ }
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2d inv = new Matrix3x2d(this).invert();
+ * inv.transform(origin.set(0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ public Vector2d origin(Vector2d origin) {
+ double s = 1.0 / (m00 * m11 - m01 * m10);
+ origin.x = (m10 * m21 - m20 * m11) * s;
+ origin.y = (m20 * m01 - m00 * m21) * s;
+ return origin;
+ }
+
+ /**
+ * Obtain the extents of the view transformation of this
matrix and store it in area
.
+ * This can be used to determine which region of the screen (i.e. the NDC space) is covered by the view.
+ *
+ * @param area
+ * will hold the view area as [minX, minY, maxX, maxY]
+ * @return area
+ */
+ public double[] viewArea(double[] area) {
+ double s = 1.0 / (m00 * m11 - m01 * m10);
+ double rm00 = m11 * s;
+ double rm01 = -m01 * s;
+ double rm10 = -m10 * s;
+ double rm11 = m00 * s;
+ double rm20 = (m10 * m21 - m20 * m11) * s;
+ double rm21 = (m20 * m01 - m00 * m21) * s;
+ double nxnyX = -rm00 - rm10;
+ double nxnyY = -rm01 - rm11;
+ double pxnyX = rm00 - rm10;
+ double pxnyY = rm01 - rm11;
+ double nxpyX = -rm00 + rm10;
+ double nxpyY = -rm01 + rm11;
+ double pxpyX = rm00 + rm10;
+ double pxpyY = rm01 + rm11;
+ double minX = nxnyX;
+ minX = minX < nxpyX ? minX : nxpyX;
+ minX = minX < pxnyX ? minX : pxnyX;
+ minX = minX < pxpyX ? minX : pxpyX;
+ double minY = nxnyY;
+ minY = minY < nxpyY ? minY : nxpyY;
+ minY = minY < pxnyY ? minY : pxnyY;
+ minY = minY < pxpyY ? minY : pxpyY;
+ double maxX = nxnyX;
+ maxX = maxX > nxpyX ? maxX : nxpyX;
+ maxX = maxX > pxnyX ? maxX : pxnyX;
+ maxX = maxX > pxpyX ? maxX : pxpyX;
+ double maxY = nxnyY;
+ maxY = maxY > nxpyY ? maxY : nxpyY;
+ maxY = maxY > pxnyY ? maxY : pxnyY;
+ maxY = maxY > pxpyY ? maxY : pxpyY;
+ area[0] = minX + rm20;
+ area[1] = minY + rm21;
+ area[2] = maxX + rm20;
+ area[3] = maxY + rm21;
+ return area;
+ }
+
+ public Vector2d positiveX(Vector2d dir) {
+ double s = m00 * m11 - m01 * m10;
+ s = 1.0 / s;
+ dir.x = m11 * s;
+ dir.y = -m01 * s;
+ return dir.normalize(dir);
+ }
+
+ public Vector2d normalizedPositiveX(Vector2d dir) {
+ dir.x = m11;
+ dir.y = -m01;
+ return dir;
+ }
+
+ public Vector2d positiveY(Vector2d dir) {
+ double s = m00 * m11 - m01 * m10;
+ s = 1.0 / s;
+ dir.x = -m10 * s;
+ dir.y = m00 * s;
+ return dir.normalize(dir);
+ }
+
+ public Vector2d normalizedPositiveY(Vector2d dir) {
+ dir.x = -m10;
+ dir.y = m00;
+ return dir;
+ }
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix3x2d)} and then the method {@link #unprojectInv(double, double, int[], Vector2d) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(double, double, int[], Vector2d)
+ * @see #invert(Matrix3x2d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ public Vector2d unproject(double winX, double winY, int[] viewport, Vector2d dest) {
+ double s = 1.0 / (m00 * m11 - m01 * m10);
+ double im00 = m11 * s;
+ double im01 = -m01 * s;
+ double im10 = -m10 * s;
+ double im11 = m00 * s;
+ double im20 = (m10 * m21 - m20 * m11) * s;
+ double im21 = (m20 * m01 - m00 * m21) * s;
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ dest.x = im00 * ndcX + im10 * ndcY + im20;
+ dest.y = im01 * ndcX + im11 * ndcY + im21;
+ return dest;
+ }
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(double, double, int[], Vector2d) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unproject(double, double, int[], Vector2d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ public Vector2d unprojectInv(double winX, double winY, int[] viewport, Vector2d dest) {
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ dest.x = m00 * ndcX + m10 * ndcY + m20;
+ dest.y = m01 * ndcX + m11 * ndcY + m21;
+ return dest;
+ }
+
+ /**
+ * Compute the extents of the coordinate system before this transformation was applied and store the resulting
+ * corner coordinates in corner
and the span vectors in xDir
and yDir
.
+ *
+ * That means, given the maximum extents of the coordinate system between [-1..+1]
in all dimensions,
+ * this method returns one corner and the length and direction of the two base axis vectors in the coordinate
+ * system before this transformation is applied, which transforms into the corner coordinates [-1, +1]
.
+ *
+ * @param corner
+ * will hold one corner of the span
+ * @param xDir
+ * will hold the direction and length of the span along the positive X axis
+ * @param yDir
+ * will hold the direction and length of the span along the positive Y axis
+ * @return this
+ */
+ public Matrix3x2d span(Vector2d corner, Vector2d xDir, Vector2d yDir) {
+ double s = 1.0 / (m00 * m11 - m01 * m10);
+ double nm00 = m11 * s, nm01 = -m01 * s, nm10 = -m10 * s, nm11 = m00 * s;
+ corner.x = -nm00 - nm10 + (m10 * m21 - m20 * m11) * s;
+ corner.y = -nm01 - nm11 + (m20 * m01 - m00 * m21) * s;
+ xDir.x = 2.0 * nm00; xDir.y = 2.0 * nm01;
+ yDir.x = 2.0 * nm10; yDir.y = 2.0 * nm11;
+ return this;
+ }
+
+ public boolean testPoint(double x, double y) {
+ double nxX = +m00, nxY = +m10, nxW = 1.0f + m20;
+ double pxX = -m00, pxY = -m10, pxW = 1.0f - m20;
+ double nyX = +m01, nyY = +m11, nyW = 1.0f + m21;
+ double pyX = -m01, pyY = -m11, pyW = 1.0f - m21;
+ return nxX * x + nxY * y + nxW >= 0 && pxX * x + pxY * y + pxW >= 0 &&
+ nyX * x + nyY * y + nyW >= 0 && pyX * x + pyY * y + pyW >= 0;
+ }
+
+ public boolean testCircle(double x, double y, double r) {
+ double invl;
+ double nxX = +m00, nxY = +m10, nxW = 1.0f + m20;
+ invl = Math.invsqrt(nxX * nxX + nxY * nxY);
+ nxX *= invl; nxY *= invl; nxW *= invl;
+ double pxX = -m00, pxY = -m10, pxW = 1.0f - m20;
+ invl = Math.invsqrt(pxX * pxX + pxY * pxY);
+ pxX *= invl; pxY *= invl; pxW *= invl;
+ double nyX = +m01, nyY = +m11, nyW = 1.0f + m21;
+ invl = Math.invsqrt(nyX * nyX + nyY * nyY);
+ nyX *= invl; nyY *= invl; nyW *= invl;
+ double pyX = -m01, pyY = -m11, pyW = 1.0f - m21;
+ invl = Math.invsqrt(pyX * pyX + pyY * pyY);
+ pyX *= invl; pyY *= invl; pyW *= invl;
+ return nxX * x + nxY * y + nxW >= -r && pxX * x + pxY * y + pxW >= -r &&
+ nyX * x + nyY * y + nyW >= -r && pyX * x + pyY * y + pyW >= -r;
+ }
+
+ public boolean testAar(double minX, double minY, double maxX, double maxY) {
+ double nxX = +m00, nxY = +m10, nxW = 1.0f + m20;
+ double pxX = -m00, pxY = -m10, pxW = 1.0f - m20;
+ double nyX = +m01, nyY = +m11, nyW = 1.0f + m21;
+ double pyX = -m01, pyY = -m11, pyW = 1.0f - m21;
+ /*
+ * This is an implementation of the "2.4 Basic intersection test" of the mentioned site.
+ * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted.
+ */
+ return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) >= -nxW &&
+ pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) >= -pxW &&
+ nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) >= -nyW &&
+ pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) >= -pyW;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(m00);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m01);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m10);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m11);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m20);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m21);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Matrix3x2d other = (Matrix3x2d) obj;
+ if (Double.doubleToLongBits(m00) != Double.doubleToLongBits(other.m00))
+ return false;
+ if (Double.doubleToLongBits(m01) != Double.doubleToLongBits(other.m01))
+ return false;
+ if (Double.doubleToLongBits(m10) != Double.doubleToLongBits(other.m10))
+ return false;
+ if (Double.doubleToLongBits(m11) != Double.doubleToLongBits(other.m11))
+ return false;
+ if (Double.doubleToLongBits(m20) != Double.doubleToLongBits(other.m20))
+ return false;
+ if (Double.doubleToLongBits(m21) != Double.doubleToLongBits(other.m21))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix3x2dc m, double delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix3x2d))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) &&
+ Math.isFinite(m10) && Math.isFinite(m11) &&
+ Math.isFinite(m20) && Math.isFinite(m21);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2dStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2dStack.java
new file mode 100644
index 000000000..1f6aa5d96
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2dStack.java
@@ -0,0 +1,186 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2018-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix3x2d} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix3x2dStack} class inherits from {@link Matrix3x2d}, so the current/top matrix is always the
+ * {@link Matrix3x2dStack}/{@link Matrix3x2d} itself. This affects all operations in {@link Matrix3x2d} that take
+ * another {@link Matrix3x2d} as parameter. If a {@link Matrix3x2dStack} is used as argument to those methods, the
+ * effective argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix3x2dStack extends Matrix3x2d implements Cloneable {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix3x2dStack(int) constructor}.
+ */
+ private Matrix3x2d[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix3x2dStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix3x2dStack} simply only consists of this
+ * {@link Matrix3x2d}
+ */
+ public Matrix3x2dStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix3x2d[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix3x2d();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix3x2dStack} instance.
+ */
+ public Matrix3x2dStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix3x2dStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix3x2dStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix3x2dStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix3x2d and Matrix3x2dStack:
+ *
+ * - Matrix3x2d.equals(Matrix3x2dStack) is true iff all the 6 matrix elements are equal
+ * - Matrix3x2dStack.equals(Matrix3x2d) is true iff all the 6 matrix elements are equal
+ * - Matrix3x2dStack.equals(Matrix3x2dStack) is true iff all 6 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix3x2dStack) {
+ Matrix3x2dStack other = (Matrix3x2dStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix3x2dStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix3x2d m = new Matrix3x2d();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix3x2dStack cloned = (Matrix3x2dStack) super.clone();
+ Matrix3x2d[] clonedMats = new Matrix3x2d[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix3x2d) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2dc.java
new file mode 100644
index 000000000..fa22f98a3
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2dc.java
@@ -0,0 +1,1196 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2017-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.util.*;
+
+
+/**
+ * Interface to a read-only view of a 3x2 matrix of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix3x2dc {
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m01();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m11();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m21();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix by assuming a third row in
+ * both matrices of (0, 0, 1)
and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d mul(Matrix3x2dc right, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix3x2d mulLocal(Matrix3x2dc left, Matrix3x2d dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ double determinant();
+
+ /**
+ * Invert the this
matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d invert(Matrix3x2d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y and store the result
+ * in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d translate(double x, double y, Matrix3x2d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y, and
+ * store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the offset to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d translate(Vector2dc offset, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x and y by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d translateLocal(Vector2dc offset, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d translateLocal(double x, double y, Matrix3x2d dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ Matrix3x2d get(Matrix3x2d dest);
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get3x3(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get3x3(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x3(ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x3(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get4x4(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get4x4(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix3x2dc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get(double[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(double[], int)}.
+ *
+ * @see #get(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get(double[] arr);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get3x3(double[] arr, int offset);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get3x3(double[], int)}.
+ *
+ * @see #get3x3(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get3x3(double[] arr);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get4x4(double[] arr, int offset);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(double[], int)}.
+ *
+ * @see #get4x4(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get4x4(double[] arr);
+
+ /**
+ * Apply scaling to this matrix by scaling the unit axes by the given x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scale(double x, double y, Matrix3x2d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scale(Vector2dc xy, Matrix3x2d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scale(Vector2fc xy, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the two base axes by the given xy
factor,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param xy
+ * the factor to scale all two base axes by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scaleLocal(double xy, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x and y
+ * factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scaleLocal(double x, double y, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given sx and
+ * sy factors while using the given (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2d().translate(ox, oy).scale(sx, sy).translate(-ox, -oy).mul(this, dest)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scaleAroundLocal(double sx, double sy, double ox, double oy, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2d().translate(ox, oy).scale(factor).translate(-ox, -oy).mul(this, dest)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3x2d scaleAroundLocal(double factor, double ox, double oy, Matrix3x2d dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling the two base axes by the given xy
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @see #scale(double, double, Matrix3x2d)
+ *
+ * @param xy
+ * the factor for the two components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scale(double xy, Matrix3x2d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin, and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(sx, sy).translate(-ox, -oy)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d scaleAround(double sx, double sy, double ox, double oy, Matrix3x2d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(factor).translate(-ox, -oy)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3x2d scaleAround(double factor, double ox, double oy, Matrix3x2d dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in that vector.
+ *
+ * @see Vector3d#mul(Matrix3x2dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3d transform(Vector3d v);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in dest
.
+ *
+ * @see Vector3d#mul(Matrix3x2dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3d transform(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform/multiply the given vector (x, y, z)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param z
+ * the z component of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3d transform(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector2dc, Vector2d)}.
+ *
+ * @see #transformPosition(Vector2dc, Vector2d)
+ * @see #transform(Vector3d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector2d transformPosition(Vector2d v);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2d)}.
+ *
+ * @see #transformPosition(Vector2d)
+ * @see #transform(Vector3dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transformPosition(Vector2dc v, Vector2d dest);
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2d)}.
+ *
+ * @see #transformPosition(Vector2d)
+ * @see #transform(Vector3dc, Vector3d)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transformPosition(double x, double y, Vector2d dest);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector2dc, Vector2d)}.
+ *
+ * @see #transformDirection(Vector2dc, Vector2d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector2d transformDirection(Vector2d v);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2d)}.
+ *
+ * @see #transformDirection(Vector2d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transformDirection(Vector2dc v, Vector2d dest);
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2d)}.
+ *
+ * @see #transformDirection(Vector2d)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d transformDirection(double x, double y, Vector2d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d rotate(double ang, Matrix3x2d dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d rotateLocal(double ang, Matrix3x2d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians about
+ * the specified rotation center (x, y)
and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(x, y, dest).rotate(ang).translate(-x, -y)
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @see #translate(double, double, Matrix3x2d)
+ * @see #rotate(double, Matrix3x2d)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the rotation center
+ * @param y
+ * the y component of the rotation center
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d rotateAbout(double ang, double x, double y, Matrix3x2d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix that rotates the given normalized fromDir
direction vector
+ * to point along the normalized toDir
, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param fromDir
+ * the normalized direction which should be rotate to point along toDir
+ * @param toDir
+ * the normalized destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d rotateTo(Vector2dc fromDir, Vector2dc toDir, Matrix3x2d dest);
+
+ /**
+ * Apply a "view" transformation to this matrix that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2d view(double left, double right, double bottom, double top, Matrix3x2d dest);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2d inv = new Matrix3x2d(this).invertAffine();
+ * inv.transform(origin.set(0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector2d origin(Vector2d origin);
+
+ /**
+ * Obtain the extents of the view transformation of this
matrix and store it in area
.
+ * This can be used to determine which region of the screen (i.e. the NDC space) is covered by the view.
+ *
+ * @param area
+ * will hold the view area as [minX, minY, maxX, maxY]
+ * @return area
+ */
+ double[] viewArea(double[] area);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2d inv = new Matrix3x2d(this).invert();
+ * inv.transformDirection(dir.set(1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector2d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector2d positiveX(Vector2d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2d inv = new Matrix3x2d(this).transpose();
+ * inv.transformDirection(dir.set(1, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector2d normalizedPositiveX(Vector2d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2d inv = new Matrix3x2d(this).invert();
+ * inv.transformDirection(dir.set(0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector2d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector2d positiveY(Vector2d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2d inv = new Matrix3x2d(this).transpose();
+ * inv.transformDirection(dir.set(0, 1));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector2d normalizedPositiveY(Vector2d dir);
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix3x2d)} and then the method {@link #unprojectInv(double, double, int[], Vector2d) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(double, double, int[], Vector2d)
+ * @see #invert(Matrix3x2d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector2d unproject(double winX, double winY, int[] viewport, Vector2d dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(double, double, int[], Vector2d) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unproject(double, double, int[], Vector2d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector2d unprojectInv(double winX, double winY, int[] viewport, Vector2d dest);
+
+ /**
+ * Test whether the given point (x, y)
is within the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given point with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the point
+ * @param y
+ * the y-coordinate of the point
+ * @return true
if the given point is inside the frustum; false
otherwise
+ */
+ boolean testPoint(double x, double y);
+
+ /**
+ * Test whether the given circle is partly or completely within or outside of the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given sphere with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the circle's center
+ * @param y
+ * the y-coordinate of the circle's center
+ * @param r
+ * the circle's radius
+ * @return true
if the given circle is partly or completely inside the frustum; false
otherwise
+ */
+ boolean testCircle(double x, double y, double r);
+
+ /**
+ * Test whether the given axis-aligned rectangle is partly or completely within or outside of the frustum defined by this
matrix.
+ * The rectangle is specified via its min and max corner coordinates.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given axis-aligned rectangle with its minimum corner coordinates (minX, minY, minZ)
+ * and maximum corner coordinates (maxX, maxY, maxZ)
given in space M
is within the clip space.
+ *
+ * Reference: Efficient View Frustum Culling
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param minX
+ * the x-coordinate of the minimum corner
+ * @param minY
+ * the y-coordinate of the minimum corner
+ * @param maxX
+ * the x-coordinate of the maximum corner
+ * @param maxY
+ * the y-coordinate of the maximum corner
+ * @return true
if the axis-aligned box is completely or partly inside of the frustum; false
otherwise
+ */
+ boolean testAar(double minX, double minY, double maxX, double maxY);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix3x2dc m, double delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2f.java
new file mode 100644
index 000000000..d090da368
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2f.java
@@ -0,0 +1,2492 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2017-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+
+/**
+ * Contains the definition of a 3x2 matrix of floats, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20
+ * m01 m11 m21
+ *
+ * @author Kai Burjack
+ */
+public class Matrix3x2f implements Matrix3x2fc, Externalizable, Cloneable {
+
+ private static final long serialVersionUID = 1L;
+
+ public float m00, m01;
+ public float m10, m11;
+ public float m20, m21;
+
+ /**
+ * Create a new {@link Matrix3x2f} and set it to {@link #identity() identity}.
+ */
+ public Matrix3x2f() {
+ this.m00 = 1.0f;
+ this.m11 = 1.0f;
+ }
+
+ /**
+ * Create a new {@link Matrix3x2f} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix3x2fc} to copy the values from
+ */
+ public Matrix3x2f(Matrix3x2fc mat) {
+ if (mat instanceof Matrix3x2f) {
+ MemUtil.INSTANCE.copy((Matrix3x2f) mat, this);
+ } else {
+ setMatrix3x2fc(mat);
+ }
+ }
+
+ /**
+ * Create a new {@link Matrix3x2f} by setting its left 2x2 submatrix to the values of the given {@link Matrix2fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix2fc}
+ */
+ public Matrix3x2f(Matrix2fc mat) {
+ if (mat instanceof Matrix2f) {
+ MemUtil.INSTANCE.copy((Matrix2f) mat, this);
+ } else {
+ setMatrix2fc(mat);
+ }
+ }
+
+ /**
+ * Create a new 3x2 matrix using the supplied float values. The order of the parameter is column-major,
+ * so the first two parameters specify the two elements of the first column.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ */
+ public Matrix3x2f(float m00, float m01,
+ float m10, float m11,
+ float m20, float m21) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m20 = m20;
+ this.m21 = m21;
+ }
+
+ /**
+ * Create a new {@link Matrix3x2f} by reading its 6 float components from the given {@link FloatBuffer}
+ * at the buffer's current position.
+ *
+ * That FloatBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link FloatBuffer} to read the matrix values from
+ */
+ public Matrix3x2f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ public float m00() {
+ return m00;
+ }
+ public float m01() {
+ return m01;
+ }
+ public float m10() {
+ return m10;
+ }
+ public float m11() {
+ return m11;
+ }
+ public float m20() {
+ return m20;
+ }
+ public float m21() {
+ return m21;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix3x2f _m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix3x2f _m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix3x2f _m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix3x2f _m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix3x2f _m20(float m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix3x2f _m21(float m21) {
+ this.m21 = m21;
+ return this;
+ }
+
+ /**
+ * Set the elements of this matrix to the ones in m
.
+ *
+ * @param m
+ * the matrix to copy the elements from
+ * @return this
+ */
+ public Matrix3x2f set(Matrix3x2fc m) {
+ if (m instanceof Matrix3x2f) {
+ MemUtil.INSTANCE.copy((Matrix3x2f) m, this);
+ } else {
+ setMatrix3x2fc(m);
+ }
+ return this;
+ }
+ private void setMatrix3x2fc(Matrix3x2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ }
+
+ /**
+ * Set the left 2x2 submatrix of this {@link Matrix3x2f} to the given {@link Matrix2fc} and don't change the other elements.
+ *
+ * @param m
+ * the 2x2 matrix
+ * @return this
+ */
+ public Matrix3x2f set(Matrix2fc m) {
+ if (m instanceof Matrix2f) {
+ MemUtil.INSTANCE.copy((Matrix2f) m, this);
+ } else {
+ setMatrix2fc(m);
+ }
+ return this;
+ }
+ private void setMatrix2fc(Matrix2fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix by assuming a third row in
+ * both matrices of (0, 0, 1)
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3x2f mul(Matrix3x2fc right) {
+ return mul(right, this);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix by assuming a third row in
+ * both matrices of (0, 0, 1)
and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f mul(Matrix3x2fc right, Matrix3x2f dest) {
+ float nm00 = m00 * right.m00() + m10 * right.m01();
+ float nm01 = m01 * right.m00() + m11 * right.m01();
+ float nm10 = m00 * right.m10() + m10 * right.m11();
+ float nm11 = m01 * right.m10() + m11 * right.m11();
+ float nm20 = m00 * right.m20() + m10 * right.m21() + m20;
+ float nm21 = m01 * right.m20() + m11 * right.m21() + m21;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix3x2f mulLocal(Matrix3x2fc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix3x2f mulLocal(Matrix3x2fc left, Matrix3x2f dest) {
+ float nm00 = left.m00() * m00 + left.m10() * m01;
+ float nm01 = left.m01() * m00 + left.m11() * m01;
+ float nm10 = left.m00() * m10 + left.m10() * m11;
+ float nm11 = left.m01() * m10 + left.m11() * m11;
+ float nm20 = left.m00() * m20 + left.m10() * m21 + left.m20();
+ float nm21 = left.m01() * m20 + left.m11() * m21 + left.m21();
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied float values. The result looks like this:
+ *
+ * m00, m10, m20
+ * m01, m11, m21
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @return this
+ */
+ public Matrix3x2f set(float m00, float m01,
+ float m10, float m11,
+ float m20, float m21) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m20 = m20;
+ this.m21 = m21;
+ return this;
+ }
+
+ /**
+ * Set the values in this matrix based on the supplied float array. The result looks like this:
+ *
+ * 0, 2, 4
+ * 1, 3, 5
+ *
+ * This method only uses the first 6 values, all others are ignored.
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix3x2f set(float m[]) {
+ MemUtil.INSTANCE.copy(m, 0, this);
+ return this;
+ }
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ public float determinant() {
+ return m00 * m11 - m01 * m10;
+ }
+
+ /**
+ * Invert this matrix by assuming a third row in this matrix of (0, 0, 1)
.
+ *
+ * @return this
+ */
+ public Matrix3x2f invert() {
+ return invert(this);
+ }
+
+ /**
+ * Invert the this
matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f invert(Matrix3x2f dest) {
+ // client must make sure that matrix is invertible
+ float s = 1.0f / (m00 * m11 - m01 * m10);
+ float nm00 = m11 * s;
+ float nm01 = -m01 * s;
+ float nm10 = -m10 * s;
+ float nm11 = m00 * s;
+ float nm20 = (m10 * m21 - m20 * m11) * s;
+ float nm21 = (m20 * m01 - m00 * m21) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix in a two-dimensional coordinate system.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to apply a translation via to an already existing transformation
+ * matrix, use {@link #translate(float, float) translate()} instead.
+ *
+ * @see #translate(float, float)
+ *
+ * @param x
+ * the units to translate in x
+ * @param y
+ * the units to translate in y
+ * @return this
+ */
+ public Matrix3x2f translation(float x, float y) {
+ m00 = 1.0f;
+ m01 = 0.0f;
+ m10 = 0.0f;
+ m11 = 1.0f;
+ m20 = x;
+ m21 = y;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix in a two-dimensional coordinate system.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to apply a translation via to an already existing transformation
+ * matrix, use {@link #translate(Vector2fc) translate()} instead.
+ *
+ * @see #translate(Vector2fc)
+ *
+ * @param offset
+ * the translation
+ * @return this
+ */
+ public Matrix3x2f translation(Vector2fc offset) {
+ return translation(offset.x(), offset.y());
+ }
+
+ /**
+ * Set only the translation components of this matrix (m20, m21)
to the given values (x, y)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(float, float)}.
+ * To apply a translation to another matrix, use {@link #translate(float, float)}.
+ *
+ * @see #translation(float, float)
+ * @see #translate(float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @return this
+ */
+ public Matrix3x2f setTranslation(float x, float y) {
+ m20 = x;
+ m21 = y;
+ return this;
+ }
+
+ /**
+ * Set only the translation components of this matrix (m20, m21)
to the given values (offset.x, offset.y)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(Vector2fc)}.
+ * To apply a translation to another matrix, use {@link #translate(Vector2fc)}.
+ *
+ * @see #translation(Vector2fc)
+ * @see #translate(Vector2fc)
+ *
+ * @param offset
+ * the new translation to set
+ * @return this
+ */
+ public Matrix3x2f setTranslation(Vector2f offset) {
+ return setTranslation(offset.x, offset.y);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y and store the result
+ * in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float)}.
+ *
+ * @see #translation(float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f translate(float x, float y, Matrix3x2f dest) {
+ float rm20 = x;
+ float rm21 = y;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ return dest;
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float)}.
+ *
+ * @see #translation(float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @return this
+ */
+ public Matrix3x2f translate(float x, float y) {
+ return translate(x, y, this);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y, and
+ * store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float)}.
+ *
+ * @see #translation(Vector2fc)
+ *
+ * @param offset
+ * the offset to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f translate(Vector2fc offset, Matrix3x2f dest) {
+ return translate(offset.x(), offset.y(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float)}.
+ *
+ * @see #translation(Vector2fc)
+ *
+ * @param offset
+ * the offset to translate
+ * @return this
+ */
+ public Matrix3x2f translate(Vector2fc offset) {
+ return translate(offset.x(), offset.y(), this);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector2fc)}.
+ *
+ * @see #translation(Vector2fc)
+ *
+ * @param offset
+ * the number of units in x and y by which to translate
+ * @return this
+ */
+ public Matrix3x2f translateLocal(Vector2fc offset) {
+ return translateLocal(offset.x(), offset.y());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector2fc)}.
+ *
+ * @see #translation(Vector2fc)
+ *
+ * @param offset
+ * the number of units in x and y by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f translateLocal(Vector2fc offset, Matrix3x2f dest) {
+ return translateLocal(offset.x(), offset.y(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(float, float)}.
+ *
+ * @see #translation(float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f translateLocal(float x, float y, Matrix3x2f dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m20 = m20 + x;
+ dest.m21 = m21 + y;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(float, float)}.
+ *
+ * @see #translation(float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @return this
+ */
+ public Matrix3x2f translateLocal(float x, float y) {
+ return translateLocal(x, y, this);
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix3x2fc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix3x2fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ public Matrix3x2f get(Matrix3x2f dest) {
+ return dest.set(this);
+ }
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public FloatBuffer get(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public FloatBuffer get3x3(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public FloatBuffer get3x3(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public ByteBuffer get3x3(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public ByteBuffer get3x3(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x3(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public FloatBuffer get4x4(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public FloatBuffer get4x4(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ public ByteBuffer get4x4(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, 0, buffer);
+ return buffer;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ public ByteBuffer get4x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+ public Matrix3x2fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Store this matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ public float[] get(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ /**
+ * Store this matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ public float[] get(float[] arr) {
+ return get(arr, 0);
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied float array at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ public float[] get3x3(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy3x3(this, arr, offset);
+ return arr;
+ }
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get3x3(float[], int)}.
+ *
+ * @see #get3x3(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ public float[] get3x3(float[] arr) {
+ return get3x3(arr, 0);
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied float array at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ public float[] get4x4(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy4x4(this, arr, offset);
+ return arr;
+ }
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(float[], int)}.
+ *
+ * @see #get4x4(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ public float[] get4x4(float[] arr) {
+ return get4x4(arr, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this matrix by reading 6 float values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix3x2f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set all values within this matrix to zero.
+ *
+ * @return this
+ */
+ public Matrix3x2f zero() {
+ MemUtil.INSTANCE.zero(this);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the identity.
+ *
+ * @return this
+ */
+ public Matrix3x2f identity() {
+ MemUtil.INSTANCE.identity(this);
+ return this;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the unit axes by the given x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f scale(float x, float y, Matrix3x2f dest) {
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x and y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix3x2f scale(float x, float y) {
+ return scale(x, y, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @return this
+ */
+ public Matrix3x2f scale(Vector2fc xy) {
+ return scale(xy.x(), xy.y(), this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f scale(Vector2fc xy, Matrix3x2f dest) {
+ return scale(xy.x(), xy.y(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling the two base axes by the given xy
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @see #scale(float, float, Matrix3x2f)
+ *
+ * @param xy
+ * the factor for the two components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f scale(float xy, Matrix3x2f dest) {
+ return scale(xy, xy, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling the two base axes by the given xyz
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @see #scale(float, float)
+ *
+ * @param xy
+ * the factor for the two components
+ * @return this
+ */
+ public Matrix3x2f scale(float xy) {
+ return scale(xy, xy);
+ }
+
+ public Matrix3x2f scaleLocal(float x, float y, Matrix3x2f dest) {
+ dest.m00 = x * m00;
+ dest.m01 = y * m01;
+ dest.m10 = x * m10;
+ dest.m11 = y * m11;
+ dest.m20 = x * m20;
+ dest.m21 = y * m21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x and y factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix3x2f scaleLocal(float x, float y) {
+ return scaleLocal(x, y, this);
+ }
+
+ public Matrix3x2f scaleLocal(float xy, Matrix3x2f dest) {
+ return scaleLocal(xy, xy, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given xy factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param xy
+ * the factor of the x and y component
+ * @return this
+ */
+ public Matrix3x2f scaleLocal(float xy) {
+ return scaleLocal(xy, xy, this);
+ }
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin, and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(sx, sy).translate(-ox, -oy)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f scaleAround(float sx, float sy, float ox, float oy, Matrix3x2f dest) {
+ float nm20 = m00 * ox + m10 * oy + m20;
+ float nm21 = m01 * ox + m11 * oy + m21;
+ dest.m00 = m00 * sx;
+ dest.m01 = m01 * sx;
+ dest.m10 = m10 * sy;
+ dest.m11 = m11 * sy;
+ dest.m20 = dest.m00 * -ox + dest.m10 * -oy + nm20;
+ dest.m21 = dest.m01 * -ox + dest.m11 * -oy + nm21;
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy).scale(sx, sy).translate(-ox, -oy)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2f scaleAround(float sx, float sy, float ox, float oy) {
+ return scaleAround(sx, sy, ox, oy, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(factor).translate(-ox, -oy)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ public Matrix3x2f scaleAround(float factor, float ox, float oy, Matrix3x2f dest) {
+ return scaleAround(factor, factor, ox, oy, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy).scale(factor).translate(-ox, -oy)
+ *
+ * @param factor
+ * the scaling factor for all axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2f scaleAround(float factor, float ox, float oy) {
+ return scaleAround(factor, factor, ox, oy, this);
+ }
+
+ public Matrix3x2f scaleAroundLocal(float sx, float sy, float ox, float oy, Matrix3x2f dest) {
+ dest.m00 = sx * m00;
+ dest.m01 = sy * m01;
+ dest.m10 = sx * m10;
+ dest.m11 = sy * m11;
+ dest.m20 = sx * m20 - sx * ox + ox;
+ dest.m21 = sy * m21 - sy * oy + oy;
+ return dest;
+ }
+
+ public Matrix3x2f scaleAroundLocal(float factor, float ox, float oy, Matrix3x2f dest) {
+ return scaleAroundLocal(factor, factor, ox, oy, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2f().translate(ox, oy).scale(sx, sy).translate(-ox, -oy).mul(this, this)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2f scaleAroundLocal(float sx, float sy, float sz, float ox, float oy, float oz) {
+ return scaleAroundLocal(sx, sy, ox, oy, this);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2f().translate(ox, oy).scale(factor).translate(-ox, -oy).mul(this, this)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix3x2f scaleAroundLocal(float factor, float ox, float oy) {
+ return scaleAroundLocal(factor, factor, ox, oy, this);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales the two base axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a matrix, use {@link #scale(float) scale()} instead.
+ *
+ * @see #scale(float)
+ *
+ * @param factor
+ * the scale factor in x and y
+ * @return this
+ */
+ public Matrix3x2f scaling(float factor) {
+ return scaling(factor, factor);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @return this
+ */
+ public Matrix3x2f scaling(float x, float y) {
+ m00 = x;
+ m01 = 0.0f;
+ m10 = 0.0f;
+ m11 = y;
+ m20 = 0.0f;
+ m21 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(float) rotate()} instead.
+ *
+ * @see #rotate(float)
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3x2f rotation(float angle) {
+ float cos = Math.cos(angle);
+ float sin = Math.sin(angle);
+ m00 = cos;
+ m10 = -sin;
+ m20 = 0.0f;
+ m01 = sin;
+ m11 = cos;
+ m21 = 0.0f;
+ return this;
+ }
+
+ /**
+ * Transform/multiply the given vector by this matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in that vector.
+ *
+ * @see Vector3f#mul(Matrix3x2fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ public Vector3f transform(Vector3f v) {
+ return v.mul(this);
+ }
+
+ /**
+ * Transform/multiply the given vector by this matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in dest
.
+ *
+ * @see Vector3f#mul(Matrix3x2fc, Vector3f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ public Vector3f transform(Vector3f v, Vector3f dest) {
+ return v.mul(this, dest);
+ }
+
+ /**
+ * Transform/multiply the given vector (x, y, z)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param z
+ * the z component of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ public Vector3f transform(float x, float y, float z, Vector3f dest) {
+ return dest.set(m00 * x + m10 * y + m20 * z, m01 * x + m11 * y + m21 * z, z);
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector2fc, Vector2f)}.
+ *
+ * @see #transformPosition(Vector2fc, Vector2f)
+ * @see #transform(Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ public Vector2f transformPosition(Vector2f v) {
+ v.set(m00 * v.x + m10 * v.y + m20,
+ m01 * v.x + m11 * v.y + m21);
+ return v;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2f)}.
+ *
+ * @see #transformPosition(Vector2f)
+ * @see #transform(Vector3f, Vector3f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2f transformPosition(Vector2fc v, Vector2f dest) {
+ dest.set(m00 * v.x() + m10 * v.y() + m20,
+ m01 * v.x() + m11 * v.y() + m21);
+ return dest;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2f)}.
+ *
+ * @see #transformPosition(Vector2f)
+ * @see #transform(Vector3f, Vector3f)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2f transformPosition(float x, float y, Vector2f dest) {
+ return dest.set(m00 * x + m10 * y + m20, m01 * x + m11 * y + m21);
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector2fc, Vector2f)}.
+ *
+ * @see #transformDirection(Vector2fc, Vector2f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ public Vector2f transformDirection(Vector2f v) {
+ v.set(m00 * v.x + m10 * v.y,
+ m01 * v.x + m11 * v.y);
+ return v;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2f)}.
+ *
+ * @see #transformDirection(Vector2f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2f transformDirection(Vector2fc v, Vector2f dest) {
+ dest.set(m00 * v.x() + m10 * v.y(),
+ m01 * v.x() + m11 * v.y());
+ return dest;
+ }
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2f)}.
+ *
+ * @see #transformDirection(Vector2f)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector2f transformDirection(float x, float y, Vector2f dest) {
+ return dest.set(m00 * x + m10 * y, m01 * x + m11 * y);
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(m00);
+ out.writeFloat(m01);
+ out.writeFloat(m10);
+ out.writeFloat(m11);
+ out.writeFloat(m20);
+ out.writeFloat(m21);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readFloat();
+ m01 = in.readFloat();
+ m10 = in.readFloat();
+ m11 = in.readFloat();
+ m20 = in.readFloat();
+ m21 = in.readFloat();
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix3x2f rotate(float ang) {
+ return rotate(ang, this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f rotate(float ang, Matrix3x2f dest) {
+ float cos = Math.cos(ang);
+ float sin = Math.sin(ang);
+ float rm00 = cos;
+ float rm01 = sin;
+ float rm10 = -sin;
+ float rm11 = cos;
+ float nm00 = m00 * rm00 + m10 * rm01;
+ float nm01 = m01 * rm00 + m11 * rm01;
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float)
+ *
+ * @param ang
+ * the angle in radians to rotate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f rotateLocal(float ang, Matrix3x2f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm00 = cos * m00 - sin * m01;
+ float nm01 = sin * m00 + cos * m01;
+ float nm10 = cos * m10 - sin * m11;
+ float nm11 = sin * m10 + cos * m11;
+ float nm20 = cos * m20 - sin * m21;
+ float nm21 = sin * m20 + cos * m21;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float)
+ *
+ * @param ang
+ * the angle in radians to rotate
+ * @return this
+ */
+ public Matrix3x2f rotateLocal(float ang) {
+ return rotateLocal(ang, this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians about
+ * the specified rotation center (x, y)
.
+ *
+ * This method is equivalent to calling: translate(x, y).rotate(ang).translate(-x, -y)
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @see #translate(float, float)
+ * @see #rotate(float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the rotation center
+ * @param y
+ * the y component of the rotation center
+ * @return this
+ */
+ public Matrix3x2f rotateAbout(float ang, float x, float y) {
+ return rotateAbout(ang, x, y, this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians about
+ * the specified rotation center (x, y)
and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(x, y, dest).rotate(ang).translate(-x, -y)
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @see #translate(float, float, Matrix3x2f)
+ * @see #rotate(float, Matrix3x2f)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the rotation center
+ * @param y
+ * the y component of the rotation center
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f rotateAbout(float ang, float x, float y, Matrix3x2f dest) {
+ float tm20 = m00 * x + m10 * y + m20;
+ float tm21 = m01 * x + m11 * y + m21;
+ float cos = Math.cos(ang);
+ float sin = Math.sin(ang);
+ float nm00 = m00 * cos + m10 * sin;
+ float nm01 = m01 * cos + m11 * sin;
+ dest.m10 = m00 * -sin + m10 * cos;
+ dest.m11 = m01 * -sin + m11 * cos;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m20 = dest.m00 * -x + dest.m10 * -y + tm20;
+ dest.m21 = dest.m01 * -x + dest.m11 * -y + tm21;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix that rotates the given normalized fromDir
direction vector
+ * to point along the normalized toDir
, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param fromDir
+ * the normalized direction which should be rotate to point along toDir
+ * @param toDir
+ * the normalized destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f rotateTo(Vector2fc fromDir, Vector2fc toDir, Matrix3x2f dest) {
+ float dot = fromDir.x() * toDir.x() + fromDir.y() * toDir.y();
+ float det = fromDir.x() * toDir.y() - fromDir.y() * toDir.x();
+ float rm00 = dot;
+ float rm01 = det;
+ float rm10 = -det;
+ float rm11 = dot;
+ float nm00 = m00 * rm00 + m10 * rm01;
+ float nm01 = m01 * rm00 + m11 * rm01;
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix that rotates the given normalized fromDir
direction vector
+ * to point along the normalized toDir
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param fromDir
+ * the normalized direction which should be rotate to point along toDir
+ * @param toDir
+ * the normalized destination direction
+ * @return this
+ */
+ public Matrix3x2f rotateTo(Vector2fc fromDir, Vector2fc toDir) {
+ return rotateTo(fromDir, toDir, this);
+ }
+
+ /**
+ * Apply a "view" transformation to this matrix that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * @see #setView(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f view(float left, float right, float bottom, float top, Matrix3x2f dest) {
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm20 = (left + right) / (left - right);
+ float rm21 = (bottom + top) / (bottom - top);
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ return dest;
+ }
+
+ /**
+ * Apply a "view" transformation to this matrix that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * @see #setView(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @return this
+ */
+ public Matrix3x2f view(float left, float right, float bottom, float top) {
+ return view(left, right, bottom, top, this);
+ }
+
+ /**
+ * Set this matrix to define a "view" transformation that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively.
+ *
+ * @see #view(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @return this
+ */
+ public Matrix3x2f setView(float left, float right, float bottom, float top) {
+ m00 = 2.0f / (right - left);
+ m01 = 0.0f;
+ m10 = 0.0f;
+ m11 = 2.0f / (top - bottom);
+ m20 = (left + right) / (left - right);
+ m21 = (bottom + top) / (bottom - top);
+ return this;
+ }
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2f inv = new Matrix3x2f(this).invert();
+ * inv.transform(origin.set(0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ public Vector2f origin(Vector2f origin) {
+ float s = 1.0f / (m00 * m11 - m01 * m10);
+ origin.x = (m10 * m21 - m20 * m11) * s;
+ origin.y = (m20 * m01 - m00 * m21) * s;
+ return origin;
+ }
+
+ /**
+ * Obtain the extents of the view transformation of this
matrix and store it in area
.
+ * This can be used to determine which region of the screen (i.e. the NDC space) is covered by the view.
+ *
+ * @param area
+ * will hold the view area as [minX, minY, maxX, maxY]
+ * @return area
+ */
+ public float[] viewArea(float[] area) {
+ float s = 1.0f / (m00 * m11 - m01 * m10);
+ float rm00 = m11 * s;
+ float rm01 = -m01 * s;
+ float rm10 = -m10 * s;
+ float rm11 = m00 * s;
+ float rm20 = (m10 * m21 - m20 * m11) * s;
+ float rm21 = (m20 * m01 - m00 * m21) * s;
+ float nxnyX = -rm00 - rm10;
+ float nxnyY = -rm01 - rm11;
+ float pxnyX = rm00 - rm10;
+ float pxnyY = rm01 - rm11;
+ float nxpyX = -rm00 + rm10;
+ float nxpyY = -rm01 + rm11;
+ float pxpyX = rm00 + rm10;
+ float pxpyY = rm01 + rm11;
+ float minX = nxnyX;
+ minX = minX < nxpyX ? minX : nxpyX;
+ minX = minX < pxnyX ? minX : pxnyX;
+ minX = minX < pxpyX ? minX : pxpyX;
+ float minY = nxnyY;
+ minY = minY < nxpyY ? minY : nxpyY;
+ minY = minY < pxnyY ? minY : pxnyY;
+ minY = minY < pxpyY ? minY : pxpyY;
+ float maxX = nxnyX;
+ maxX = maxX > nxpyX ? maxX : nxpyX;
+ maxX = maxX > pxnyX ? maxX : pxnyX;
+ maxX = maxX > pxpyX ? maxX : pxpyX;
+ float maxY = nxnyY;
+ maxY = maxY > nxpyY ? maxY : nxpyY;
+ maxY = maxY > pxnyY ? maxY : pxnyY;
+ maxY = maxY > pxpyY ? maxY : pxpyY;
+ area[0] = minX + rm20;
+ area[1] = minY + rm21;
+ area[2] = maxX + rm20;
+ area[3] = maxY + rm21;
+ return area;
+ }
+
+ public Vector2f positiveX(Vector2f dir) {
+ float s = m00 * m11 - m01 * m10;
+ s = 1.0f / s;
+ dir.x = m11 * s;
+ dir.y = -m01 * s;
+ return dir.normalize(dir);
+ }
+
+ public Vector2f normalizedPositiveX(Vector2f dir) {
+ dir.x = m11;
+ dir.y = -m01;
+ return dir;
+ }
+
+ public Vector2f positiveY(Vector2f dir) {
+ float s = m00 * m11 - m01 * m10;
+ s = 1.0f / s;
+ dir.x = -m10 * s;
+ dir.y = m00 * s;
+ return dir.normalize(dir);
+ }
+
+ public Vector2f normalizedPositiveY(Vector2f dir) {
+ dir.x = -m10;
+ dir.y = m00;
+ return dir;
+ }
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix3x2f)} and then the method {@link #unprojectInv(float, float, int[], Vector2f) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(float, float, int[], Vector2f)
+ * @see #invert(Matrix3x2f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ public Vector2f unproject(float winX, float winY, int[] viewport, Vector2f dest) {
+ float s = 1.0f / (m00 * m11 - m01 * m10);
+ float im00 = m11 * s;
+ float im01 = -m01 * s;
+ float im10 = -m10 * s;
+ float im11 = m00 * s;
+ float im20 = (m10 * m21 - m20 * m11) * s;
+ float im21 = (m20 * m01 - m00 * m21) * s;
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ dest.x = im00 * ndcX + im10 * ndcY + im20;
+ dest.y = im01 * ndcX + im11 * ndcY + im21;
+ return dest;
+ }
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(float, float, int[], Vector2f) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unproject(float, float, int[], Vector2f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ public Vector2f unprojectInv(float winX, float winY, int[] viewport, Vector2f dest) {
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ dest.x = m00 * ndcX + m10 * ndcY + m20;
+ dest.y = m01 * ndcX + m11 * ndcY + m21;
+ return dest;
+ }
+
+ /**
+ * Apply shearing to this matrix by shearing along the X axis using the Y axis factor yFactor
.
+ *
+ * @param yFactor
+ * the factor for the Y component to shear along the X axis
+ * @return this
+ */
+ public Matrix3x2f shearX(float yFactor) {
+ return shearX(yFactor, this);
+ }
+
+ /**
+ * Apply shearing to this matrix by shearing along the X axis using the Y axis factor yFactor
,
+ * and store the result in dest
.
+ *
+ * @param yFactor
+ * the factor for the Y component to shear along the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f shearX(float yFactor, Matrix3x2f dest) {
+ float nm10 = m00 * yFactor + m10;
+ float nm11 = m01 * yFactor + m11;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Apply shearing to this matrix by shearing along the Y axis using the X axis factor xFactor
.
+ *
+ * @param xFactor
+ * the factor for the X component to shear along the Y axis
+ * @return this
+ */
+ public Matrix3x2f shearY(float xFactor) {
+ return shearY(xFactor, this);
+ }
+
+ /**
+ * Apply shearing to this matrix by shearing along the Y axis using the X axis factor xFactor
,
+ * and store the result in dest
.
+ *
+ * @param xFactor
+ * the factor for the X component to shear along the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3x2f shearY(float xFactor, Matrix3x2f dest) {
+ float nm00 = m00 + m10 * xFactor;
+ float nm01 = m01 + m11 * xFactor;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ return dest;
+ }
+
+ /**
+ * Compute the extents of the coordinate system before this transformation was applied and store the resulting
+ * corner coordinates in corner
and the span vectors in xDir
and yDir
.
+ *
+ * That means, given the maximum extents of the coordinate system between [-1..+1]
in all dimensions,
+ * this method returns one corner and the length and direction of the two base axis vectors in the coordinate
+ * system before this transformation is applied, which transforms into the corner coordinates [-1, +1]
.
+ *
+ * @param corner
+ * will hold one corner of the span
+ * @param xDir
+ * will hold the direction and length of the span along the positive X axis
+ * @param yDir
+ * will hold the direction and length of the span along the positive Y axis
+ * @return this
+ */
+ public Matrix3x2f span(Vector2f corner, Vector2f xDir, Vector2f yDir) {
+ float s = 1.0f / (m00 * m11 - m01 * m10);
+ float nm00 = m11 * s, nm01 = -m01 * s, nm10 = -m10 * s, nm11 = m00 * s;
+ corner.x = -nm00 - nm10 + (m10 * m21 - m20 * m11) * s;
+ corner.y = -nm01 - nm11 + (m20 * m01 - m00 * m21) * s;
+ xDir.x = 2.0f * nm00; xDir.y = 2.0f * nm01;
+ yDir.x = 2.0f * nm10; yDir.y = 2.0f * nm11;
+ return this;
+ }
+
+ public boolean testPoint(float x, float y) {
+ float nxX = +m00, nxY = +m10, nxW = 1.0f + m20;
+ float pxX = -m00, pxY = -m10, pxW = 1.0f - m20;
+ float nyX = +m01, nyY = +m11, nyW = 1.0f + m21;
+ float pyX = -m01, pyY = -m11, pyW = 1.0f - m21;
+ return nxX * x + nxY * y + nxW >= 0 && pxX * x + pxY * y + pxW >= 0 &&
+ nyX * x + nyY * y + nyW >= 0 && pyX * x + pyY * y + pyW >= 0;
+ }
+
+ public boolean testCircle(float x, float y, float r) {
+ float invl;
+ float nxX = +m00, nxY = +m10, nxW = 1.0f + m20;
+ invl = Math.invsqrt(nxX * nxX + nxY * nxY);
+ nxX *= invl; nxY *= invl; nxW *= invl;
+ float pxX = -m00, pxY = -m10, pxW = 1.0f - m20;
+ invl = Math.invsqrt(pxX * pxX + pxY * pxY);
+ pxX *= invl; pxY *= invl; pxW *= invl;
+ float nyX = +m01, nyY = +m11, nyW = 1.0f + m21;
+ invl = Math.invsqrt(nyX * nyX + nyY * nyY);
+ nyX *= invl; nyY *= invl; nyW *= invl;
+ float pyX = -m01, pyY = -m11, pyW = 1.0f - m21;
+ invl = Math.invsqrt(pyX * pyX + pyY * pyY);
+ pyX *= invl; pyY *= invl; pyW *= invl;
+ return nxX * x + nxY * y + nxW >= -r && pxX * x + pxY * y + pxW >= -r &&
+ nyX * x + nyY * y + nyW >= -r && pyX * x + pyY * y + pyW >= -r;
+ }
+
+ public boolean testAar(float minX, float minY, float maxX, float maxY) {
+ float nxX = +m00, nxY = +m10, nxW = 1.0f + m20;
+ float pxX = -m00, pxY = -m10, pxW = 1.0f - m20;
+ float nyX = +m01, nyY = +m11, nyW = 1.0f + m21;
+ float pyX = -m01, pyY = -m11, pyW = 1.0f - m21;
+ /*
+ * This is an implementation of the "2.4 Basic intersection test" of the mentioned site.
+ * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted.
+ */
+ return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) >= -nxW &&
+ pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) >= -pxW &&
+ nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) >= -nyW &&
+ pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) >= -pyW;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(m00);
+ result = prime * result + Float.floatToIntBits(m01);
+ result = prime * result + Float.floatToIntBits(m10);
+ result = prime * result + Float.floatToIntBits(m11);
+ result = prime * result + Float.floatToIntBits(m20);
+ result = prime * result + Float.floatToIntBits(m21);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Matrix3x2f other = (Matrix3x2f) obj;
+ if (Float.floatToIntBits(m00) != Float.floatToIntBits(other.m00))
+ return false;
+ if (Float.floatToIntBits(m01) != Float.floatToIntBits(other.m01))
+ return false;
+ if (Float.floatToIntBits(m10) != Float.floatToIntBits(other.m10))
+ return false;
+ if (Float.floatToIntBits(m11) != Float.floatToIntBits(other.m11))
+ return false;
+ if (Float.floatToIntBits(m20) != Float.floatToIntBits(other.m20))
+ return false;
+ if (Float.floatToIntBits(m21) != Float.floatToIntBits(other.m21))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix3x2fc m, float delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix3x2f))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) &&
+ Math.isFinite(m10) && Math.isFinite(m11) &&
+ Math.isFinite(m20) && Math.isFinite(m21);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2fStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2fStack.java
new file mode 100644
index 000000000..349f3260e
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2fStack.java
@@ -0,0 +1,186 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2018-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix3x2f} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix3x2fStack} class inherits from {@link Matrix3x2f}, so the current/top matrix is always the
+ * {@link Matrix3x2fStack}/{@link Matrix3x2f} itself. This affects all operations in {@link Matrix3x2f} that take
+ * another {@link Matrix3x2f} as parameter. If a {@link Matrix3x2fStack} is used as argument to those methods, the
+ * effective argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix3x2fStack extends Matrix3x2f {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix3x2fStack(int) constructor}.
+ */
+ private Matrix3x2f[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix3x2fStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix3x2fStack} simply only consists of this
+ * {@link Matrix3x2f}
+ */
+ public Matrix3x2fStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix3x2f[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix3x2f();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix3x2fStack} instance.
+ */
+ public Matrix3x2fStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix3x2fStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix3x2fStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix3x2fStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix3x2f and Matrix3x2fStack:
+ *
+ * - Matrix3x2f.equals(Matrix3x2fStack) is true iff all the 6 matrix elements are equal
+ * - Matrix3x2fStack.equals(Matrix3x2f) is true iff all the 6 matrix elements are equal
+ * - Matrix3x2fStack.equals(Matrix3x2fStack) is true iff all 6 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix3x2fStack) {
+ Matrix3x2fStack other = (Matrix3x2fStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix3x2fStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix3x2f m = new Matrix3x2f();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix3x2fStack cloned = (Matrix3x2fStack) super.clone();
+ Matrix3x2f[] clonedMats = new Matrix3x2f[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix3x2f) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2fc.java
new file mode 100644
index 000000000..833f93cec
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix3x2fc.java
@@ -0,0 +1,1180 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2017-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+
+/**
+ * Interface to a read-only view of a 3x2 matrix of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix3x2fc {
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m01();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m11();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m21();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix by assuming a third row in
+ * both matrices of (0, 0, 1)
and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f mul(Matrix3x2fc right, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix3x2f mulLocal(Matrix3x2fc left, Matrix3x2f dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ float determinant();
+
+ /**
+ * Invert the this
matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f invert(Matrix3x2f dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y and store the result
+ * in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f translate(float x, float y, Matrix3x2f dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of units in x and y, and
+ * store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the offset to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f translate(Vector2fc offset, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x and y by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f translateLocal(Vector2fc offset, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f translateLocal(float x, float y, Matrix3x2f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ Matrix3x2f get(Matrix3x2f dest);
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x3(FloatBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x3(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x3(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x3(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x3(ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x3(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x4(FloatBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x4(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(ByteBuffer buffer);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix3x2fc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get3x3(float[] arr, int offset);
+
+ /**
+ * Store this matrix as an equivalent 3x3 matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get3x3(float[], int)}.
+ *
+ * @see #get3x3(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get3x3(float[] arr);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get4x4(float[] arr, int offset);
+
+ /**
+ * Store this matrix as an equivalent 4x4 matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(float[], int)}.
+ *
+ * @see #get4x4(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get4x4(float[] arr);
+
+ /**
+ * Apply scaling to this matrix by scaling the unit axes by the given x and y and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scale(float x, float y, Matrix3x2f dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xy
factors
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @param xy
+ * the factors of the x and y component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scale(Vector2fc xy, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given sx and
+ * sy factors while using the given (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2f().translate(ox, oy).scale(sx, sy).translate(-ox, -oy).mul(this, dest)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scaleAroundLocal(float sx, float sy, float ox, float oy, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix3x2f().translate(ox, oy).scale(factor).translate(-ox, -oy).mul(this, dest)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3x2f scaleAroundLocal(float factor, float ox, float oy, Matrix3x2f dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling the two base axes by the given xy
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the scaling will be applied first!
+ *
+ * @see #scale(float, float, Matrix3x2f)
+ *
+ * @param xy
+ * the factor for the two components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scale(float xy, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the two base axes by the given xy
factor,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param xy
+ * the factor to scale all two base axes by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scaleLocal(float xy, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x and y
+ * factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scaleLocal(float x, float y, Matrix3x2f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx and
+ * sy factors while using (ox, oy)
as the scaling origin, and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(sx, sy).translate(-ox, -oy)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f scaleAround(float sx, float sy, float ox, float oy, Matrix3x2f dest);
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given factor
+ * while using (ox, oy)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, dest).scale(factor).translate(-ox, -oy)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix3x2f scaleAround(float factor, float ox, float oy, Matrix3x2f dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix by assuming a third row in this matrix of (0, 0, 1)
+ * and store the result in that vector.
+ *
+ * @see Vector3f#mul(Matrix3x2fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transform(Vector3f v);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in dest
.
+ *
+ * @see Vector3f#mul(Matrix3x2fc, Vector3f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3f transform(Vector3f v, Vector3f dest);
+
+ /**
+ * Transform/multiply the given vector (x, y, z)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param z
+ * the z component of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3f transform(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector2fc, Vector2f)}.
+ *
+ * @see #transformPosition(Vector2fc, Vector2f)
+ * @see #transform(Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector2f transformPosition(Vector2f v);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2f)}.
+ *
+ * @see #transformPosition(Vector2f)
+ * @see #transform(Vector3f, Vector3f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transformPosition(Vector2fc v, Vector2f dest);
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 1.0, so it
+ * will represent a position/location in 2D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector2f)}.
+ *
+ * @see #transformPosition(Vector2f)
+ * @see #transform(Vector3f, Vector3f)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transformPosition(float x, float y, Vector2f dest);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector2fc, Vector2f)}.
+ *
+ * @see #transformDirection(Vector2fc, Vector2f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector2f transformDirection(Vector2f v);
+
+ /**
+ * Transform/multiply the given 2D-vector, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2f)}.
+ *
+ * @see #transformDirection(Vector2f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transformDirection(Vector2fc v, Vector2f dest);
+
+ /**
+ * Transform/multiply the given 2D-vector (x, y)
, as if it was a 3D-vector with z=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 2D-vector is treated as a 3D-vector with its z-component being 0.0
, so it
+ * will represent a direction in 2D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector2f)}.
+ *
+ * @see #transformDirection(Vector2f)
+ *
+ * @param x
+ * the x component of the vector to transform
+ * @param y
+ * the y component of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f transformDirection(float x, float y, Vector2f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f rotate(float ang, Matrix3x2f dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f rotateLocal(float ang, Matrix3x2f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix by rotating the given amount of radians about
+ * the specified rotation center (x, y)
and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(x, y, dest).rotate(ang).translate(-x, -y)
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @see #translate(float, float, Matrix3x2f)
+ * @see #rotate(float, Matrix3x2f)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the rotation center
+ * @param y
+ * the y component of the rotation center
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f rotateAbout(float ang, float x, float y, Matrix3x2f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix that rotates the given normalized fromDir
direction vector
+ * to point along the normalized toDir
, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the rotation will be applied first!
+ *
+ * @param fromDir
+ * the normalized direction which should be rotate to point along toDir
+ * @param toDir
+ * the normalized destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f rotateTo(Vector2fc fromDir, Vector2fc toDir, Matrix3x2f dest);
+
+ /**
+ * Apply a "view" transformation to this matrix that maps the given (left, bottom)
and
+ * (right, top)
corners to (-1, -1)
and (1, 1)
respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * @param left
+ * the distance from the center to the left view edge
+ * @param right
+ * the distance from the center to the right view edge
+ * @param bottom
+ * the distance from the center to the bottom view edge
+ * @param top
+ * the distance from the center to the top view edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3x2f view(float left, float right, float bottom, float top, Matrix3x2f dest);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2f inv = new Matrix3x2f(this).invertAffine();
+ * inv.transform(origin.set(0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector2f origin(Vector2f origin);
+
+ /**
+ * Obtain the extents of the view transformation of this
matrix and store it in area
.
+ * This can be used to determine which region of the screen (i.e. the NDC space) is covered by the view.
+ *
+ * @param area
+ * will hold the view area as [minX, minY, maxX, maxY]
+ * @return area
+ */
+ float[] viewArea(float[] area);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2f inv = new Matrix3x2f(this).invert();
+ * inv.transformDirection(dir.set(1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector2f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector2f positiveX(Vector2f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2f inv = new Matrix3x2f(this).transpose();
+ * inv.transformDirection(dir.set(1, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector2f normalizedPositiveX(Vector2f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2f inv = new Matrix3x2f(this).invert();
+ * inv.transformDirection(dir.set(0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector2f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector2f positiveY(Vector2f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 2x2 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix3x2f inv = new Matrix3x2f(this).transpose();
+ * inv.transformDirection(dir.set(0, 1));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector2f normalizedPositiveY(Vector2f dir);
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix3x2f)} and then the method {@link #unprojectInv(float, float, int[], Vector2f) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(float, float, int[], Vector2f)
+ * @see #invert(Matrix3x2f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector2f unproject(float winX, float winY, int[] viewport, Vector2f dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(float, float, int[], Vector2f) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unproject(float, float, int[], Vector2f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector2f unprojectInv(float winX, float winY, int[] viewport, Vector2f dest);
+
+ /**
+ * Test whether the given point (x, y)
is within the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given point with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the point
+ * @param y
+ * the y-coordinate of the point
+ * @return true
if the given point is inside the frustum; false
otherwise
+ */
+ boolean testPoint(float x, float y);
+
+ /**
+ * Test whether the given circle is partly or completely within or outside of the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given sphere with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the circle's center
+ * @param y
+ * the y-coordinate of the circle's center
+ * @param r
+ * the circle's radius
+ * @return true
if the given circle is partly or completely inside the frustum; false
otherwise
+ */
+ boolean testCircle(float x, float y, float r);
+
+ /**
+ * Test whether the given axis-aligned rectangle is partly or completely within or outside of the frustum defined by this
matrix.
+ * The rectangle is specified via its min and max corner coordinates.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given axis-aligned rectangle with its minimum corner coordinates (minX, minY, minZ)
+ * and maximum corner coordinates (maxX, maxY, maxZ)
given in space M
is within the clip space.
+ *
+ * Reference: Efficient View Frustum Culling
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param minX
+ * the x-coordinate of the minimum corner
+ * @param minY
+ * the y-coordinate of the minimum corner
+ * @param maxX
+ * the x-coordinate of the maximum corner
+ * @param maxY
+ * the y-coordinate of the maximum corner
+ * @return true
if the axis-aligned box is completely or partly inside of the frustum; false
otherwise
+ */
+ boolean testAar(float minX, float minY, float maxX, float maxY);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix3x2fc m, float delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4d.java
new file mode 100644
index 000000000..781810144
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4d.java
@@ -0,0 +1,16604 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a 4x4 Matrix of doubles, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20 m30
+ * m01 m11 m21 m31
+ * m02 m12 m22 m32
+ * m03 m13 m23 m33
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Matrix4d implements Externalizable, Cloneable, Matrix4dc {
+
+ private static final long serialVersionUID = 1L;
+
+ double m00, m01, m02, m03;
+ double m10, m11, m12, m13;
+ double m20, m21, m22, m23;
+ double m30, m31, m32, m33;
+
+ int properties;
+
+ /**
+ * Create a new {@link Matrix4d} and set it to {@link #identity() identity}.
+ */
+ public Matrix4d() {
+ _m00(1.0).
+ _m11(1.0).
+ _m22(1.0).
+ _m33(1.0).
+ properties = PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ }
+
+ /**
+ * Create a new {@link Matrix4d} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix4dc} to copy the values from
+ */
+ public Matrix4d(Matrix4dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4d} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix4fc} to copy the values from
+ */
+ public Matrix4d(Matrix4fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4d} and set its upper 4x3 submatrix to the given matrix mat
+ * and all other elements to identity.
+ *
+ * @param mat
+ * the {@link Matrix4x3dc} to copy the values from
+ */
+ public Matrix4d(Matrix4x3dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4d} and set its upper 4x3 submatrix to the given matrix mat
+ * and all other elements to identity.
+ *
+ * @param mat
+ * the {@link Matrix4x3fc} to copy the values from
+ */
+ public Matrix4d(Matrix4x3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4d} by setting its uppper left 3x3 submatrix to the values of the given {@link Matrix3dc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix3dc}
+ */
+ public Matrix4d(Matrix3dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new 4x4 matrix using the supplied double values.
+ *
+ * The matrix layout will be:
+ * m00, m10, m20, m30
+ * m01, m11, m21, m31
+ * m02, m12, m22, m32
+ * m03, m13, m23, m33
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m02
+ * the value of m02
+ * @param m03
+ * the value of m03
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m12
+ * the value of m12
+ * @param m13
+ * the value of m13
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ * @param m22
+ * the value of m22
+ * @param m23
+ * the value of m23
+ * @param m30
+ * the value of m30
+ * @param m31
+ * the value of m31
+ * @param m32
+ * the value of m32
+ * @param m33
+ * the value of m33
+ */
+ public Matrix4d(double m00, double m01, double m02, double m03,
+ double m10, double m11, double m12, double m13,
+ double m20, double m21, double m22, double m23,
+ double m30, double m31, double m32, double m33) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m03 = m03;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m13 = m13;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ this.m23 = m23;
+ this.m30 = m30;
+ this.m31 = m31;
+ this.m32 = m32;
+ this.m33 = m33;
+ determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4d} by reading its 16 double components from the given {@link DoubleBuffer}
+ * at the buffer's current position.
+ *
+ * That DoubleBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link DoubleBuffer} to read the matrix values from
+ */
+ public Matrix4d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4d} and initialize its four columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ */
+ public Matrix4d(Vector4d col0, Vector4d col1, Vector4d col2, Vector4d col3) {
+ set(col0, col1, col2, col3);
+ }
+
+ /**
+ * Assume the given properties about this matrix.
+ *
+ * Use one or multiple of 0, {@link Matrix4dc#PROPERTY_IDENTITY},
+ * {@link Matrix4dc#PROPERTY_TRANSLATION}, {@link Matrix4dc#PROPERTY_AFFINE},
+ * {@link Matrix4dc#PROPERTY_PERSPECTIVE}, {@link Matrix4fc#PROPERTY_ORTHONORMAL}.
+ *
+ * @param properties
+ * bitset of the properties to assume about this matrix
+ * @return this
+ */
+ public Matrix4d assume(int properties) {
+ this.properties = (byte) properties;
+ return this;
+ }
+
+ /**
+ * Compute and set the matrix properties returned by {@link #properties()} based
+ * on the current matrix element values.
+ *
+ * @return this
+ */
+ public Matrix4d determineProperties() {
+ int properties = 0;
+ if (m03 == 0.0 && m13 == 0.0) {
+ if (m23 == 0.0 && m33 == 1.0) {
+ properties |= PROPERTY_AFFINE;
+ if (m00 == 1.0 && m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m11 == 1.0 && m12 == 0.0 && m20 == 0.0
+ && m21 == 0.0 && m22 == 1.0) {
+ properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ if (m30 == 0.0 && m31 == 0.0 && m32 == 0.0)
+ properties |= PROPERTY_IDENTITY;
+ }
+ /*
+ * We do not determine orthogonality, since it would require arbitrary epsilons
+ * and is rather expensive (6 dot products) in the worst case.
+ */
+ } else if (m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m12 == 0.0 && m20 == 0.0 && m21 == 0.0 && m30 == 0.0
+ && m31 == 0.0 && m33 == 0.0) {
+ properties |= PROPERTY_PERSPECTIVE;
+ }
+ }
+ this.properties = properties;
+ return this;
+ }
+
+ public int properties() {
+ return properties;
+ }
+
+ public double m00() {
+ return m00;
+ }
+ public double m01() {
+ return m01;
+ }
+ public double m02() {
+ return m02;
+ }
+ public double m03() {
+ return m03;
+ }
+ public double m10() {
+ return m10;
+ }
+ public double m11() {
+ return m11;
+ }
+ public double m12() {
+ return m12;
+ }
+ public double m13() {
+ return m13;
+ }
+ public double m20() {
+ return m20;
+ }
+ public double m21() {
+ return m21;
+ }
+ public double m22() {
+ return m22;
+ }
+ public double m23() {
+ return m23;
+ }
+ public double m30() {
+ return m30;
+ }
+ public double m31() {
+ return m31;
+ }
+ public double m32() {
+ return m32;
+ }
+ public double m33() {
+ return m33;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix4d m00(double m00) {
+ this.m00 = m00;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m00 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix4d m01(double m01) {
+ this.m01 = m01;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m01 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ public Matrix4d m02(double m02) {
+ this.m02 = m02;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m02 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 3.
+ *
+ * @param m03
+ * the new value
+ * @return this
+ */
+ public Matrix4d m03(double m03) {
+ this.m03 = m03;
+ if (m03 != 0.0)
+ properties = 0;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix4d m10(double m10) {
+ this.m10 = m10;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m10 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix4d m11(double m11) {
+ this.m11 = m11;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m11 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ public Matrix4d m12(double m12) {
+ this.m12 = m12;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m12 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 3.
+ *
+ * @param m13
+ * the new value
+ * @return this
+ */
+ public Matrix4d m13(double m13) {
+ this.m13 = m13;
+ if (m03 != 0.0)
+ properties = 0;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ public Matrix4d m20(double m20) {
+ this.m20 = m20;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m20 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ public Matrix4d m21(double m21) {
+ this.m21 = m21;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m21 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ public Matrix4d m22(double m22) {
+ this.m22 = m22;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m22 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 3.
+ *
+ * @param m23
+ * the new value
+ * @return this
+ */
+ public Matrix4d m23(double m23) {
+ this.m23 = m23;
+ if (m23 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ public Matrix4d m30(double m30) {
+ this.m30 = m30;
+ if (m30 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ public Matrix4d m31(double m31) {
+ this.m31 = m31;
+ if (m31 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ public Matrix4d m32(double m32) {
+ this.m32 = m32;
+ if (m32 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 3.
+ *
+ * @param m33
+ * the new value
+ * @return this
+ */
+ public Matrix4d m33(double m33) {
+ this.m33 = m33;
+ if (m33 != 0.0)
+ properties &= ~(PROPERTY_PERSPECTIVE);
+ if (m33 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL | PROPERTY_AFFINE);
+ return this;
+ }
+
+ Matrix4d _properties(int properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix4d _m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix4d _m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ Matrix4d _m02(double m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 3 without updating the properties of the matrix.
+ *
+ * @param m03
+ * the new value
+ * @return this
+ */
+ Matrix4d _m03(double m03) {
+ this.m03 = m03;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix4d _m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix4d _m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ Matrix4d _m12(double m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 3 without updating the properties of the matrix.
+ *
+ * @param m13
+ * the new value
+ * @return this
+ */
+ Matrix4d _m13(double m13) {
+ this.m13 = m13;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix4d _m20(double m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix4d _m21(double m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ Matrix4d _m22(double m22) {
+ this.m22 = m22;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 3 without updating the properties of the matrix.
+ *
+ * @param m23
+ * the new value
+ * @return this
+ */
+ Matrix4d _m23(double m23) {
+ this.m23 = m23;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ Matrix4d _m30(double m30) {
+ this.m30 = m30;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ Matrix4d _m31(double m31) {
+ this.m31 = m31;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ Matrix4d _m32(double m32) {
+ this.m32 = m32;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 3 without updating the properties of the matrix.
+ *
+ * @param m33
+ * the new value
+ * @return this
+ */
+ Matrix4d _m33(double m33) {
+ this.m33 = m33;
+ return this;
+ }
+
+ /**
+ * Reset this matrix to the identity.
+ *
+ * Please note that if a call to {@link #identity()} is immediately followed by a call to:
+ * {@link #translate(double, double, double) translate},
+ * {@link #rotate(double, double, double, double) rotate},
+ * {@link #scale(double, double, double) scale},
+ * {@link #perspective(double, double, double, double) perspective},
+ * {@link #frustum(double, double, double, double, double, double) frustum},
+ * {@link #ortho(double, double, double, double, double, double) ortho},
+ * {@link #ortho2D(double, double, double, double) ortho2D},
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt},
+ * {@link #lookAlong(double, double, double, double, double, double) lookAlong},
+ * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with:
+ * {@link #translation(double, double, double) translation},
+ * {@link #rotation(double, double, double, double) rotation},
+ * {@link #scaling(double, double, double) scaling},
+ * {@link #setPerspective(double, double, double, double) setPerspective},
+ * {@link #setFrustum(double, double, double, double, double, double) setFrustum},
+ * {@link #setOrtho(double, double, double, double, double, double) setOrtho},
+ * {@link #setOrtho2D(double, double, double, double) setOrtho2D},
+ * {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt},
+ * {@link #setLookAlong(double, double, double, double, double, double) setLookAlong},
+ * or any of their overloads.
+ *
+ * @return this
+ */
+ public Matrix4d identity() {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return this;
+ _identity();
+ properties = PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+ private void _identity() {
+ _m00(1.0).
+ _m10(0.0).
+ _m20(0.0).
+ _m30(0.0).
+ _m01(0.0).
+ _m11(1.0).
+ _m21(0.0).
+ _m31(0.0).
+ _m02(0.0).
+ _m12(0.0).
+ _m22(1.0).
+ _m32(0.0).
+ _m03(0.0).
+ _m13(0.0).
+ _m23(0.0).
+ _m33(1.0);
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * @see #Matrix4d(Matrix4dc)
+ * @see #get(Matrix4d)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4d set(Matrix4dc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m03(m.m03()).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m13(m.m13()).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22()).
+ _m23(m.m23()).
+ _m30(m.m30()).
+ _m31(m.m31()).
+ _m32(m.m32()).
+ _m33(m.m33()).
+ _properties(m.properties());
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * @see #Matrix4d(Matrix4fc)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4d set(Matrix4fc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m03(m.m03()).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m13(m.m13()).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22()).
+ _m23(m.m23()).
+ _m30(m.m30()).
+ _m31(m.m31()).
+ _m32(m.m32()).
+ _m33(m.m33()).
+ _properties(m.properties());
+ }
+
+ /**
+ * Store the values of the transpose of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the transposed values from
+ * @return this
+ */
+ public Matrix4d setTransposed(Matrix4dc m) {
+ if ((m.properties() & PROPERTY_IDENTITY) != 0)
+ return this.identity();
+ return setTransposedInternal(m);
+ }
+ private Matrix4d setTransposedInternal(Matrix4dc m) {
+ double nm10 = m.m01(), nm12 = m.m21(), nm13 = m.m31();
+ double nm20 = m.m02(), nm21 = m.m12(), nm30 = m.m03();
+ double nm31 = m.m13(), nm32 = m.m23();
+ return this
+ ._m00(m.m00())._m01(m.m10())._m02(m.m20())._m03(m.m30())
+ ._m10(nm10)._m11(m.m11())._m12(nm12)._m13(nm13)
+ ._m20(nm20)._m21(nm21)._m22(m.m22())._m23(m.m32())
+ ._m30(nm30)._m31(nm31)._m32(nm32)._m33(m.m33())
+ ._properties(m.properties() & PROPERTY_IDENTITY);
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix
+ * and set the other matrix elements to identity.
+ *
+ * @see #Matrix4d(Matrix4x3dc)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4d set(Matrix4x3dc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m03(0.0).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m13(0.0).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22()).
+ _m23(0.0).
+ _m30(m.m30()).
+ _m31(m.m31()).
+ _m32(m.m32()).
+ _m33(1.0).
+ _properties(m.properties() | PROPERTY_AFFINE);
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix
+ * and set the other matrix elements to identity.
+ *
+ * @see #Matrix4d(Matrix4x3fc)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4d set(Matrix4x3fc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m03(0.0).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m13(0.0).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22()).
+ _m23(0.0).
+ _m30(m.m30()).
+ _m31(m.m31()).
+ _m32(m.m32()).
+ _m33(1.0).
+ _properties(m.properties() | PROPERTY_AFFINE);
+ }
+
+ /**
+ * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3dc}
+ * and the rest to identity.
+ *
+ * @see #Matrix4d(Matrix3dc)
+ *
+ * @param mat
+ * the {@link Matrix3dc}
+ * @return this
+ */
+ public Matrix4d set(Matrix3dc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m03(0.0).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m13(0.0).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _m23(0.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m32(0.0).
+ _m33(1.0).
+ _properties(PROPERTY_AFFINE);
+ }
+
+ /**
+ * Set the upper left 3x3 submatrix of this {@link Matrix4d} to that of the given {@link Matrix4dc}
+ * and don't change the other elements.
+ *
+ * @param mat
+ * the {@link Matrix4dc}
+ * @return this
+ */
+ public Matrix4d set3x3(Matrix4dc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _properties(properties & mat.properties() & ~(PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Set the upper 4x3 submatrix of this {@link Matrix4d} to the given {@link Matrix4x3dc}
+ * and don't change the other elements.
+ *
+ * @see Matrix4x3dc#get(Matrix4d)
+ *
+ * @param mat
+ * the {@link Matrix4x3dc}
+ * @return this
+ */
+ public Matrix4d set4x3(Matrix4x3dc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _m30(mat.m30()).
+ _m31(mat.m31()).
+ _m32(mat.m32()).
+ _properties(properties & mat.properties() & ~(PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Set the upper 4x3 submatrix of this {@link Matrix4d} to the given {@link Matrix4x3fc}
+ * and don't change the other elements.
+ *
+ * @see Matrix4x3fc#get(Matrix4d)
+ *
+ * @param mat
+ * the {@link Matrix4x3fc}
+ * @return this
+ */
+ public Matrix4d set4x3(Matrix4x3fc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _m30(mat.m30()).
+ _m31(mat.m31()).
+ _m32(mat.m32()).
+ _properties(properties & mat.properties() & ~(PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Set the upper 4x3 submatrix of this {@link Matrix4d} to the upper 4x3 submatrix of the given {@link Matrix4dc}
+ * and don't change the other elements.
+ *
+ * @param mat
+ * the {@link Matrix4dc}
+ * @return this
+ */
+ public Matrix4d set4x3(Matrix4dc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _m30(mat.m30()).
+ _m31(mat.m31()).
+ _m32(mat.m32()).
+ _properties(properties & mat.properties() & ~(PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Matrix4d set(AxisAngle4f axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ _m00(c + x*x*omc).
+ _m11(c + y*y*omc).
+ _m22(c + z*z*omc);
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ _m10(tmp1 - tmp2).
+ _m01(tmp1 + tmp2);
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ _m20(tmp1 + tmp2).
+ _m02(tmp1 - tmp2);
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ _m21(tmp1 - tmp2).
+ _m12(tmp1 + tmp2).
+ _m03(0.0).
+ _m13(0.0).
+ _m23(0.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m32(0.0).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Matrix4d set(AxisAngle4d axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ _m00(c + x*x*omc).
+ _m11(c + y*y*omc).
+ _m22(c + z*z*omc);
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ _m10(tmp1 - tmp2).
+ _m01(tmp1 + tmp2);
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ _m20(tmp1 + tmp2).
+ _m02(tmp1 - tmp2);
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ _m21(tmp1 - tmp2).
+ _m12(tmp1 + tmp2).
+ _m03(0.0).
+ _m13(0.0).
+ _m23(0.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m32(0.0).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaternionfc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param q
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4d set(Quaternionfc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniondc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param q
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4d set(Quaterniondc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @return this
+ */
+ public Matrix4d mul(Matrix4dc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4d mul(Matrix4dc right, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0 && (right.properties() & PROPERTY_AFFINE) != 0)
+ return mulTranslationAffine(right, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0 && (right.properties() & PROPERTY_AFFINE) != 0)
+ return mulAffine(right, dest);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0 && (right.properties() & PROPERTY_AFFINE) != 0)
+ return mulPerspectiveAffine(right, dest);
+ else if ((right.properties() & PROPERTY_AFFINE) != 0)
+ return mulAffineR(right, dest);
+ return mul0(right, dest);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * This method neither assumes nor checks for any matrix properties of this
or right
+ * and will always perform a complete 4x4 matrix multiplication. This method should only be used whenever the
+ * multiplied matrices do not have any properties for which there are optimized multiplication methods available.
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4d mul0(Matrix4dc right) {
+ return mul0(right, this);
+ }
+
+ public Matrix4d mul0(Matrix4dc right, Matrix4d dest) {
+ double nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), Math.fma(m20, right.m02(), m30 * right.m03())));
+ double nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), Math.fma(m21, right.m02(), m31 * right.m03())));
+ double nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), Math.fma(m22, right.m02(), m32 * right.m03())));
+ double nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), Math.fma(m23, right.m02(), m33 * right.m03())));
+ double nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), Math.fma(m20, right.m12(), m30 * right.m13())));
+ double nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), Math.fma(m21, right.m12(), m31 * right.m13())));
+ double nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), Math.fma(m22, right.m12(), m32 * right.m13())));
+ double nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), Math.fma(m23, right.m12(), m33 * right.m13())));
+ double nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), Math.fma(m20, right.m22(), m30 * right.m23())));
+ double nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), Math.fma(m21, right.m22(), m31 * right.m23())));
+ double nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), Math.fma(m22, right.m22(), m32 * right.m23())));
+ double nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), Math.fma(m23, right.m22(), m33 * right.m23())));
+ double nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30 * right.m33())));
+ double nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31 * right.m33())));
+ double nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32 * right.m33())));
+ double nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33 * right.m33())));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Multiply this matrix by the matrix with the supplied elements.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r03
+ * the m03 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r13
+ * the m13 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @param r23
+ * the m23 element of the right matrix
+ * @param r30
+ * the m30 element of the right matrix
+ * @param r31
+ * the m31 element of the right matrix
+ * @param r32
+ * the m32 element of the right matrix
+ * @param r33
+ * the m33 element of the right matrix
+ * @return this
+ */
+ public Matrix4d mul(
+ double r00, double r01, double r02, double r03,
+ double r10, double r11, double r12, double r13,
+ double r20, double r21, double r22, double r23,
+ double r30, double r31, double r32, double r33) {
+ return mul(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, this);
+ }
+
+ public Matrix4d mul(
+ double r00, double r01, double r02, double r03,
+ double r10, double r11, double r12, double r13,
+ double r20, double r21, double r22, double r23,
+ double r30, double r31, double r32, double r33, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return mulAffineL(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest);
+ return mulGeneric(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest);
+ }
+ private Matrix4d mulAffineL(
+ double r00, double r01, double r02, double r03,
+ double r10, double r11, double r12, double r13,
+ double r20, double r21, double r22, double r23,
+ double r30, double r31, double r32, double r33, Matrix4d dest) {
+ double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03)));
+ double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03)));
+ double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03)));
+ double nm03 = r03;
+ double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13)));
+ double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13)));
+ double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13)));
+ double nm13 = r13;
+ double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23)));
+ double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23)));
+ double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23)));
+ double nm23 = r23;
+ double nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33)));
+ double nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33)));
+ double nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33)));
+ double nm33 = r33;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(PROPERTY_AFFINE);
+ }
+ private Matrix4d mulGeneric(
+ double r00, double r01, double r02, double r03,
+ double r10, double r11, double r12, double r13,
+ double r20, double r21, double r22, double r23,
+ double r30, double r31, double r32, double r33, Matrix4d dest) {
+ double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03)));
+ double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03)));
+ double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03)));
+ double nm03 = Math.fma(m03, r00, Math.fma(m13, r01, Math.fma(m23, r02, m33 * r03)));
+ double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13)));
+ double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13)));
+ double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13)));
+ double nm13 = Math.fma(m03, r10, Math.fma(m13, r11, Math.fma(m23, r12, m33 * r13)));
+ double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23)));
+ double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23)));
+ double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23)));
+ double nm23 = Math.fma(m03, r20, Math.fma(m13, r21, Math.fma(m23, r22, m33 * r23)));
+ double nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33)));
+ double nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33)));
+ double nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33)));
+ double nm33 = Math.fma(m03, r30, Math.fma(m13, r31, Math.fma(m23, r32, m33 * r33)));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Multiply this matrix by the 3x3 matrix with the supplied elements expanded to a 4x4 matrix with
+ * all other matrix elements set to identity.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @return this
+ */
+ public Matrix4d mul3x3(
+ double r00, double r01, double r02,
+ double r10, double r11, double r12,
+ double r20, double r21, double r22) {
+ return mul3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, this);
+ }
+ public Matrix4d mul3x3(
+ double r00, double r01, double r02,
+ double r10, double r11, double r12,
+ double r20, double r21, double r22, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(r00, r01, r02, 0, r10, r11, r12, 0, r20, r21, r22, 0, 0, 0, 0, 1);
+ return mulGeneric3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, dest);
+ }
+ private Matrix4d mulGeneric3x3(
+ double r00, double r01, double r02,
+ double r10, double r11, double r12,
+ double r20, double r21, double r22, Matrix4d dest) {
+ double nm00 = Math.fma(m00, r00, Math.fma(m10, r01, m20 * r02));
+ double nm01 = Math.fma(m01, r00, Math.fma(m11, r01, m21 * r02));
+ double nm02 = Math.fma(m02, r00, Math.fma(m12, r01, m22 * r02));
+ double nm03 = Math.fma(m03, r00, Math.fma(m13, r01, m23 * r02));
+ double nm10 = Math.fma(m00, r10, Math.fma(m10, r11, m20 * r12));
+ double nm11 = Math.fma(m01, r10, Math.fma(m11, r11, m21 * r12));
+ double nm12 = Math.fma(m02, r10, Math.fma(m12, r11, m22 * r12));
+ double nm13 = Math.fma(m03, r10, Math.fma(m13, r11, m23 * r12));
+ double nm20 = Math.fma(m00, r20, Math.fma(m10, r21, m20 * r22));
+ double nm21 = Math.fma(m01, r20, Math.fma(m11, r21, m21 * r22));
+ double nm22 = Math.fma(m02, r20, Math.fma(m12, r21, m22 * r22));
+ double nm23 = Math.fma(m03, r20, Math.fma(m13, r21, m23 * r22));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(this.properties & PROPERTY_AFFINE);
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4d mulLocal(Matrix4dc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix4d mulLocal(Matrix4dc left, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(left);
+ else if ((left.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_AFFINE) != 0 && (left.properties() & PROPERTY_AFFINE) != 0)
+ return mulLocalAffine(left, dest);
+ return mulLocalGeneric(left, dest);
+ }
+ private Matrix4d mulLocalGeneric(Matrix4dc left, Matrix4d dest) {
+ double nm00 = Math.fma(left.m00(), m00, Math.fma(left.m10(), m01, Math.fma(left.m20(), m02, left.m30() * m03)));
+ double nm01 = Math.fma(left.m01(), m00, Math.fma(left.m11(), m01, Math.fma(left.m21(), m02, left.m31() * m03)));
+ double nm02 = Math.fma(left.m02(), m00, Math.fma(left.m12(), m01, Math.fma(left.m22(), m02, left.m32() * m03)));
+ double nm03 = Math.fma(left.m03(), m00, Math.fma(left.m13(), m01, Math.fma(left.m23(), m02, left.m33() * m03)));
+ double nm10 = Math.fma(left.m00(), m10, Math.fma(left.m10(), m11, Math.fma(left.m20(), m12, left.m30() * m13)));
+ double nm11 = Math.fma(left.m01(), m10, Math.fma(left.m11(), m11, Math.fma(left.m21(), m12, left.m31() * m13)));
+ double nm12 = Math.fma(left.m02(), m10, Math.fma(left.m12(), m11, Math.fma(left.m22(), m12, left.m32() * m13)));
+ double nm13 = Math.fma(left.m03(), m10, Math.fma(left.m13(), m11, Math.fma(left.m23(), m12, left.m33() * m13)));
+ double nm20 = Math.fma(left.m00(), m20, Math.fma(left.m10(), m21, Math.fma(left.m20(), m22, left.m30() * m23)));
+ double nm21 = Math.fma(left.m01(), m20, Math.fma(left.m11(), m21, Math.fma(left.m21(), m22, left.m31() * m23)));
+ double nm22 = Math.fma(left.m02(), m20, Math.fma(left.m12(), m21, Math.fma(left.m22(), m22, left.m32() * m23)));
+ double nm23 = Math.fma(left.m03(), m20, Math.fma(left.m13(), m21, Math.fma(left.m23(), m22, left.m33() * m23)));
+ double nm30 = Math.fma(left.m00(), m30, Math.fma(left.m10(), m31, Math.fma(left.m20(), m32, left.m30() * m33)));
+ double nm31 = Math.fma(left.m01(), m30, Math.fma(left.m11(), m31, Math.fma(left.m21(), m32, left.m31() * m33)));
+ double nm32 = Math.fma(left.m02(), m30, Math.fma(left.m12(), m31, Math.fma(left.m22(), m32, left.m32() * m33)));
+ double nm33 = Math.fma(left.m03(), m30, Math.fma(left.m13(), m31, Math.fma(left.m23(), m32, left.m33() * m33)));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in this
.
+ *
+ * This method assumes that this
matrix and the given left
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of left
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @return this
+ */
+ public Matrix4d mulLocalAffine(Matrix4dc left) {
+ return mulLocalAffine(left, this);
+ }
+
+ public Matrix4d mulLocalAffine(Matrix4dc left, Matrix4d dest) {
+ double nm00 = left.m00() * m00 + left.m10() * m01 + left.m20() * m02;
+ double nm01 = left.m01() * m00 + left.m11() * m01 + left.m21() * m02;
+ double nm02 = left.m02() * m00 + left.m12() * m01 + left.m22() * m02;
+ double nm03 = left.m03();
+ double nm10 = left.m00() * m10 + left.m10() * m11 + left.m20() * m12;
+ double nm11 = left.m01() * m10 + left.m11() * m11 + left.m21() * m12;
+ double nm12 = left.m02() * m10 + left.m12() * m11 + left.m22() * m12;
+ double nm13 = left.m13();
+ double nm20 = left.m00() * m20 + left.m10() * m21 + left.m20() * m22;
+ double nm21 = left.m01() * m20 + left.m11() * m21 + left.m21() * m22;
+ double nm22 = left.m02() * m20 + left.m12() * m21 + left.m22() * m22;
+ double nm23 = left.m23();
+ double nm30 = left.m00() * m30 + left.m10() * m31 + left.m20() * m32 + left.m30();
+ double nm31 = left.m01() * m30 + left.m11() * m31 + left.m21() * m32 + left.m31();
+ double nm32 = left.m02() * m30 + left.m12() * m31 + left.m22() * m32 + left.m32();
+ double nm33 = left.m33();
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(PROPERTY_AFFINE);
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * The last row of the right
matrix is assumed to be (0, 0, 0, 1)
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4d mul(Matrix4x3dc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4d mul(Matrix4x3dc right, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return mulTranslation(right, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return mulAffine(right, dest);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return mulPerspectiveAffine(right, dest);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4d mulTranslation(Matrix4x3dc right, Matrix4d dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m03(m03)
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m13(m13)
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m23(m23)
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (right.properties() & PROPERTY_ORTHONORMAL));
+ }
+ private Matrix4d mulAffine(Matrix4x3dc right, Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ double m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ double rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ double rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ double rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ double rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m03(m03)
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m13(m13)
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m23(m23)
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (this.properties & right.properties() & PROPERTY_ORTHONORMAL));
+ }
+ private Matrix4d mulGeneric(Matrix4x3dc right, Matrix4d dest) {
+ double nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ double nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ double nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ double nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), m23 * right.m02()));
+ double nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ double nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ double nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ double nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), m23 * right.m12()));
+ double nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ double nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ double nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ double nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), m23 * right.m22()));
+ double nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30)));
+ double nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31)));
+ double nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32)));
+ double nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33)));
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+ public Matrix4d mulPerspectiveAffine(Matrix4x3dc view, Matrix4d dest) {
+ double lm00 = m00, lm11 = m11, lm22 = m22, lm23 = m23;
+ dest._m00(lm00 * view.m00())._m01(lm11 * view.m01())._m02(lm22 * view.m02())._m03(lm23 * view.m02()).
+ _m10(lm00 * view.m10())._m11(lm11 * view.m11())._m12(lm22 * view.m12())._m13(lm23 * view.m12()).
+ _m20(lm00 * view.m20())._m21(lm11 * view.m21())._m22(lm22 * view.m22())._m23(lm23 * view.m22()).
+ _m30(lm00 * view.m30())._m31(lm11 * view.m31())._m32(lm22 * view.m32() + m32)._m33(lm23 * view.m32())
+ ._properties(0);
+ return dest;
+ }
+
+ public Matrix4d mul(Matrix4x3fc right, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4d mulGeneric(Matrix4x3fc right, Matrix4d dest) {
+ double nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ double nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ double nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ double nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), m23 * right.m02()));
+ double nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ double nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ double nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ double nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), m23 * right.m12()));
+ double nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ double nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ double nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ double nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), m23 * right.m22()));
+ double nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30)));
+ double nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31)));
+ double nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32)));
+ double nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33)));
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4d mul(Matrix3x2dc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4d mul(Matrix3x2dc right, Matrix4d dest) {
+ double nm00 = m00 * right.m00() + m10 * right.m01();
+ double nm01 = m01 * right.m00() + m11 * right.m01();
+ double nm02 = m02 * right.m00() + m12 * right.m01();
+ double nm03 = m03 * right.m00() + m13 * right.m01();
+ double nm10 = m00 * right.m10() + m10 * right.m11();
+ double nm11 = m01 * right.m10() + m11 * right.m11();
+ double nm12 = m02 * right.m10() + m12 * right.m11();
+ double nm13 = m03 * right.m10() + m13 * right.m11();
+ double nm30 = m00 * right.m20() + m10 * right.m21() + m30;
+ double nm31 = m01 * right.m20() + m11 * right.m21() + m31;
+ double nm32 = m02 * right.m20() + m12 * right.m21() + m32;
+ double nm33 = m03 * right.m20() + m13 * right.m21() + m33;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4d mul(Matrix3x2fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4d mul(Matrix3x2fc right, Matrix4d dest) {
+ double nm00 = m00 * right.m00() + m10 * right.m01();
+ double nm01 = m01 * right.m00() + m11 * right.m01();
+ double nm02 = m02 * right.m00() + m12 * right.m01();
+ double nm03 = m03 * right.m00() + m13 * right.m01();
+ double nm10 = m00 * right.m10() + m10 * right.m11();
+ double nm11 = m01 * right.m10() + m11 * right.m11();
+ double nm12 = m02 * right.m10() + m12 * right.m11();
+ double nm13 = m03 * right.m10() + m13 * right.m11();
+ double nm30 = m00 * right.m20() + m10 * right.m21() + m30;
+ double nm31 = m01 * right.m20() + m11 * right.m21() + m31;
+ double nm32 = m02 * right.m20() + m12 * right.m21() + m32;
+ double nm33 = m03 * right.m20() + m13 * right.m21() + m33;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied parameter matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @return this
+ */
+ public Matrix4d mul(Matrix4f right) {
+ return mul(right, this);
+ }
+
+ public Matrix4d mul(Matrix4fc right, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4d mulGeneric(Matrix4fc right, Matrix4d dest) {
+ double nm00 = m00 * right.m00() + m10 * right.m01() + m20 * right.m02() + m30 * right.m03();
+ double nm01 = m01 * right.m00() + m11 * right.m01() + m21 * right.m02() + m31 * right.m03();
+ double nm02 = m02 * right.m00() + m12 * right.m01() + m22 * right.m02() + m32 * right.m03();
+ double nm03 = m03 * right.m00() + m13 * right.m01() + m23 * right.m02() + m33 * right.m03();
+ double nm10 = m00 * right.m10() + m10 * right.m11() + m20 * right.m12() + m30 * right.m13();
+ double nm11 = m01 * right.m10() + m11 * right.m11() + m21 * right.m12() + m31 * right.m13();
+ double nm12 = m02 * right.m10() + m12 * right.m11() + m22 * right.m12() + m32 * right.m13();
+ double nm13 = m03 * right.m10() + m13 * right.m11() + m23 * right.m12() + m33 * right.m13();
+ double nm20 = m00 * right.m20() + m10 * right.m21() + m20 * right.m22() + m30 * right.m23();
+ double nm21 = m01 * right.m20() + m11 * right.m21() + m21 * right.m22() + m31 * right.m23();
+ double nm22 = m02 * right.m20() + m12 * right.m21() + m22 * right.m22() + m32 * right.m23();
+ double nm23 = m03 * right.m20() + m13 * right.m21() + m23 * right.m22() + m33 * right.m23();
+ double nm30 = m00 * right.m30() + m10 * right.m31() + m20 * right.m32() + m30 * right.m33();
+ double nm31 = m01 * right.m30() + m11 * right.m31() + m21 * right.m32() + m31 * right.m33();
+ double nm32 = m02 * right.m30() + m12 * right.m31() + m22 * right.m32() + m32 * right.m33();
+ double nm33 = m03 * right.m30() + m13 * right.m31() + m23 * right.m32() + m33 * right.m33();
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied {@link #isAffine() affine} view
matrix.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the {@link #isAffine() affine} matrix to multiply this
symmetric perspective projection matrix by
+ * @return this
+ */
+ public Matrix4d mulPerspectiveAffine(Matrix4dc view) {
+ return mulPerspectiveAffine(view, this);
+ }
+
+ public Matrix4d mulPerspectiveAffine(Matrix4dc view, Matrix4d dest) {
+ double nm00 = m00 * view.m00(), nm01 = m11 * view.m01(), nm02 = m22 * view.m02(), nm03 = m23 * view.m02();
+ double nm10 = m00 * view.m10(), nm11 = m11 * view.m11(), nm12 = m22 * view.m12(), nm13 = m23 * view.m12();
+ double nm20 = m00 * view.m20(), nm21 = m11 * view.m21(), nm22 = m22 * view.m22(), nm23 = m23 * view.m22();
+ double nm30 = m00 * view.m30(), nm31 = m11 * view.m31(), nm32 = m22 * view.m32() + m32, nm33 = m23 * view.m32();
+ return dest
+ ._m00(nm00)._m01(nm01)._m02(nm02)._m03(nm03)
+ ._m10(nm10)._m11(nm11)._m12(nm12)._m13(nm13)
+ ._m20(nm20)._m21(nm21)._m22(nm22)._m23(nm23)
+ ._m30(nm30)._m31(nm31)._m32(nm32)._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, which is assumed to be {@link #isAffine() affine}, and store the result in this
.
+ *
+ * This method assumes that the given right
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @return this
+ */
+ public Matrix4d mulAffineR(Matrix4dc right) {
+ return mulAffineR(right, this);
+ }
+
+ public Matrix4d mulAffineR(Matrix4dc right, Matrix4d dest) {
+ double nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ double nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ double nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ double nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), m23 * right.m02()));
+ double nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ double nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ double nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ double nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), m23 * right.m12()));
+ double nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ double nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ double nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ double nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), m23 * right.m22()));
+ double nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30)));
+ double nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31)));
+ double nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32)));
+ double nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33)));
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in this
.
+ *
+ * This method assumes that this
matrix and the given right
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @return this
+ */
+ public Matrix4d mulAffine(Matrix4dc right) {
+ return mulAffine(right, this);
+ }
+
+ public Matrix4d mulAffine(Matrix4dc right, Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ double m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ double rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ double rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ double rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ double rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m03(m03)
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m13(m13)
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m23(m23)
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (this.properties & right.properties() & PROPERTY_ORTHONORMAL));
+ }
+
+ public Matrix4d mulTranslationAffine(Matrix4dc right, Matrix4d dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m03(m03)
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m13(m13)
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m23(m23)
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (right.properties() & PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied {@link #isAffine() affine} view
matrix.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the affine matrix which to multiply this
with
+ * @return this
+ */
+ public Matrix4d mulOrthoAffine(Matrix4dc view) {
+ return mulOrthoAffine(view, this);
+ }
+
+ public Matrix4d mulOrthoAffine(Matrix4dc view, Matrix4d dest) {
+ double nm00 = m00 * view.m00();
+ double nm01 = m11 * view.m01();
+ double nm02 = m22 * view.m02();
+ double nm03 = 0.0;
+ double nm10 = m00 * view.m10();
+ double nm11 = m11 * view.m11();
+ double nm12 = m22 * view.m12();
+ double nm13 = 0.0;
+ double nm20 = m00 * view.m20();
+ double nm21 = m11 * view.m21();
+ double nm22 = m22 * view.m22();
+ double nm23 = 0.0;
+ double nm30 = m00 * view.m30() + m30;
+ double nm31 = m11 * view.m31() + m31;
+ double nm32 = m22 * view.m32() + m32;
+ double nm33 = 1.0;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(PROPERTY_AFFINE);
+ return dest;
+ }
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * by first multiplying each component of other
's 4x3 submatrix by otherFactor
and
+ * adding that result to this
.
+ *
+ * The matrix other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's 4x3 components
+ * @return this
+ */
+ public Matrix4d fma4x3(Matrix4dc other, double otherFactor) {
+ return fma4x3(other, otherFactor, this);
+ }
+
+ public Matrix4d fma4x3(Matrix4dc other, double otherFactor, Matrix4d dest) {
+ dest._m00(Math.fma(other.m00(), otherFactor, m00))
+ ._m01(Math.fma(other.m01(), otherFactor, m01))
+ ._m02(Math.fma(other.m02(), otherFactor, m02))
+ ._m03(m03)
+ ._m10(Math.fma(other.m10(), otherFactor, m10))
+ ._m11(Math.fma(other.m11(), otherFactor, m11))
+ ._m12(Math.fma(other.m12(), otherFactor, m12))
+ ._m13(m13)
+ ._m20(Math.fma(other.m20(), otherFactor, m20))
+ ._m21(Math.fma(other.m21(), otherFactor, m21))
+ ._m22(Math.fma(other.m22(), otherFactor, m22))
+ ._m23(m23)
+ ._m30(Math.fma(other.m30(), otherFactor, m30))
+ ._m31(Math.fma(other.m31(), otherFactor, m31))
+ ._m32(Math.fma(other.m32(), otherFactor, m32))
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4d add(Matrix4dc other) {
+ return add(other, this);
+ }
+
+ public Matrix4d add(Matrix4dc other, Matrix4d dest) {
+ dest._m00(m00 + other.m00())
+ ._m01(m01 + other.m01())
+ ._m02(m02 + other.m02())
+ ._m03(m03 + other.m03())
+ ._m10(m10 + other.m10())
+ ._m11(m11 + other.m11())
+ ._m12(m12 + other.m12())
+ ._m13(m13 + other.m13())
+ ._m20(m20 + other.m20())
+ ._m21(m21 + other.m21())
+ ._m22(m22 + other.m22())
+ ._m23(m23 + other.m23())
+ ._m30(m30 + other.m30())
+ ._m31(m31 + other.m31())
+ ._m32(m32 + other.m32())
+ ._m33(m33 + other.m33())
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4d sub(Matrix4dc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix4d sub(Matrix4dc subtrahend, Matrix4d dest) {
+ dest._m00(m00 - subtrahend.m00())
+ ._m01(m01 - subtrahend.m01())
+ ._m02(m02 - subtrahend.m02())
+ ._m03(m03 - subtrahend.m03())
+ ._m10(m10 - subtrahend.m10())
+ ._m11(m11 - subtrahend.m11())
+ ._m12(m12 - subtrahend.m12())
+ ._m13(m13 - subtrahend.m13())
+ ._m20(m20 - subtrahend.m20())
+ ._m21(m21 - subtrahend.m21())
+ ._m22(m22 - subtrahend.m22())
+ ._m23(m23 - subtrahend.m23())
+ ._m30(m30 - subtrahend.m30())
+ ._m31(m31 - subtrahend.m31())
+ ._m32(m32 - subtrahend.m32())
+ ._m33(m33 - subtrahend.m33())
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix4d mulComponentWise(Matrix4dc other) {
+ return mulComponentWise(other, this);
+ }
+
+ public Matrix4d mulComponentWise(Matrix4dc other, Matrix4d dest) {
+ dest._m00(m00 * other.m00())
+ ._m01(m01 * other.m01())
+ ._m02(m02 * other.m02())
+ ._m03(m03 * other.m03())
+ ._m10(m10 * other.m10())
+ ._m11(m11 * other.m11())
+ ._m12(m12 * other.m12())
+ ._m13(m13 * other.m13())
+ ._m20(m20 * other.m20())
+ ._m21(m21 * other.m21())
+ ._m22(m22 * other.m22())
+ ._m23(m23 * other.m23())
+ ._m30(m30 * other.m30())
+ ._m31(m31 * other.m31())
+ ._m32(m32 * other.m32())
+ ._m33(m33 * other.m33())
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4d add4x3(Matrix4dc other) {
+ return add4x3(other, this);
+ }
+
+ public Matrix4d add4x3(Matrix4dc other, Matrix4d dest) {
+ dest._m00(m00 + other.m00())
+ ._m01(m01 + other.m01())
+ ._m02(m02 + other.m02())
+ ._m03(m03)
+ ._m10(m10 + other.m10())
+ ._m11(m11 + other.m11())
+ ._m12(m12 + other.m12())
+ ._m13(m13)
+ ._m20(m20 + other.m20())
+ ._m21(m21 + other.m21())
+ ._m22(m22 + other.m22())
+ ._m23(m23)
+ ._m30(m30 + other.m30())
+ ._m31(m31 + other.m31())
+ ._m32(m32 + other.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4d add4x3(Matrix4fc other) {
+ return add4x3(other, this);
+ }
+
+ public Matrix4d add4x3(Matrix4fc other, Matrix4d dest) {
+ dest._m00(m00 + other.m00())
+ ._m01(m01 + other.m01())
+ ._m02(m02 + other.m02())
+ ._m03(m03)
+ ._m10(m10 + other.m10())
+ ._m11(m11 + other.m11())
+ ._m12(m12 + other.m12())
+ ._m13(m13)
+ ._m20(m20 + other.m20())
+ ._m21(m21 + other.m21())
+ ._m22(m22 + other.m22())
+ ._m23(m23)
+ ._m30(m30 + other.m30())
+ ._m31(m31 + other.m31())
+ ._m32(m32 + other.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract the upper 4x3 submatrices of subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4d sub4x3(Matrix4dc subtrahend) {
+ return sub4x3(subtrahend, this);
+ }
+
+ public Matrix4d sub4x3(Matrix4dc subtrahend, Matrix4d dest) {
+ dest._m00(m00 - subtrahend.m00())
+ ._m01(m01 - subtrahend.m01())
+ ._m02(m02 - subtrahend.m02())
+ ._m03(m03)
+ ._m10(m10 - subtrahend.m10())
+ ._m11(m11 - subtrahend.m11())
+ ._m12(m12 - subtrahend.m12())
+ ._m13(m13)
+ ._m20(m20 - subtrahend.m20())
+ ._m21(m21 - subtrahend.m21())
+ ._m22(m22 - subtrahend.m22())
+ ._m23(m23)
+ ._m30(m30 - subtrahend.m30())
+ ._m31(m31 - subtrahend.m31())
+ ._m32(m32 - subtrahend.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply the upper 4x3 submatrices of this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix4d mul4x3ComponentWise(Matrix4dc other) {
+ return mul4x3ComponentWise(other, this);
+ }
+
+ public Matrix4d mul4x3ComponentWise(Matrix4dc other, Matrix4d dest) {
+ dest._m00(m00 * other.m00())
+ ._m01(m01 * other.m01())
+ ._m02(m02 * other.m02())
+ ._m03(m03)
+ ._m10(m10 * other.m10())
+ ._m11(m11 * other.m11())
+ ._m12(m12 * other.m12())
+ ._m13(m13)
+ ._m20(m20 * other.m20())
+ ._m21(m21 * other.m21())
+ ._m22(m22 * other.m22())
+ ._m23(m23)
+ ._m30(m30 * other.m30())
+ ._m31(m31 * other.m31())
+ ._m32(m32 * other.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /** Set the values within this matrix to the supplied double values. The matrix will look like this:
+ *
+ * m00, m10, m20, m30
+ * m01, m11, m21, m31
+ * m02, m12, m22, m32
+ * m03, m13, m23, m33
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m02
+ * the new value of m02
+ * @param m03
+ * the new value of m03
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m12
+ * the new value of m12
+ * @param m13
+ * the new value of m13
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @param m22
+ * the new value of m22
+ * @param m23
+ * the new value of m23
+ * @param m30
+ * the new value of m30
+ * @param m31
+ * the new value of m31
+ * @param m32
+ * the new value of m32
+ * @param m33
+ * the new value of m33
+ * @return this
+ */
+ public Matrix4d set(double m00, double m01, double m02,double m03,
+ double m10, double m11, double m12, double m13,
+ double m20, double m21, double m22, double m23,
+ double m30, double m31, double m32, double m33) {
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m20 = m20;
+ this.m30 = m30;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m21 = m21;
+ this.m31 = m31;
+ this.m02 = m02;
+ this.m12 = m12;
+ this.m22 = m22;
+ this.m32 = m32;
+ this.m03 = m03;
+ this.m13 = m13;
+ this.m23 = m23;
+ this.m33 = m33;
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 4, 8, 12
+ * 1, 5, 9, 13
+ * 2, 6, 10, 14
+ * 3, 7, 11, 15
+ *
+ * @see #set(double[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4d set(double m[], int off) {
+ return
+ _m00(m[off+0]).
+ _m01(m[off+1]).
+ _m02(m[off+2]).
+ _m03(m[off+3]).
+ _m10(m[off+4]).
+ _m11(m[off+5]).
+ _m12(m[off+6]).
+ _m13(m[off+7]).
+ _m20(m[off+8]).
+ _m21(m[off+9]).
+ _m22(m[off+10]).
+ _m23(m[off+11]).
+ _m30(m[off+12]).
+ _m31(m[off+13]).
+ _m32(m[off+14]).
+ _m33(m[off+15]).
+ determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 4, 8, 12
+ * 1, 5, 9, 13
+ * 2, 6, 10, 14
+ * 3, 7, 11, 15
+ *
+ * @see #set(double[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4d set(double m[]) {
+ return set(m, 0);
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 4, 8, 12
+ * 1, 5, 9, 13
+ * 2, 6, 10, 14
+ * 3, 7, 11, 15
+ *
+ * @see #set(float[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4d set(float m[], int off) {
+ return
+ _m00(m[off+0]).
+ _m01(m[off+1]).
+ _m02(m[off+2]).
+ _m03(m[off+3]).
+ _m10(m[off+4]).
+ _m11(m[off+5]).
+ _m12(m[off+6]).
+ _m13(m[off+7]).
+ _m20(m[off+8]).
+ _m21(m[off+9]).
+ _m22(m[off+10]).
+ _m23(m[off+11]).
+ _m30(m[off+12]).
+ _m31(m[off+13]).
+ _m32(m[off+14]).
+ _m33(m[off+15]).
+ determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 4, 8, 12
+ * 1, 5, 9, 13
+ * 2, 6, 10, 14
+ * 3, 7, 11, 15
+ *
+ * @see #set(float[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4d set(float m[]) {
+ return set(m, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d setFloats(ByteBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d setFloats(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 double values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return determineProperties();
+ }
+
+ /**
+ * Set the four columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ * @return this
+ */
+ public Matrix4d set(Vector4d col0, Vector4d col1, Vector4d col2, Vector4d col3) {
+ return
+ _m00(col0.x()).
+ _m01(col0.y()).
+ _m02(col0.z()).
+ _m03(col0.w()).
+ _m10(col1.x()).
+ _m11(col1.y()).
+ _m12(col1.z()).
+ _m13(col1.w()).
+ _m20(col2.x()).
+ _m21(col2.y()).
+ _m22(col2.z()).
+ _m23(col2.w()).
+ _m30(col3.x()).
+ _m31(col3.y()).
+ _m32(col3.z()).
+ _m33(col3.w()).
+ determineProperties();
+ }
+
+ public double determinant() {
+ if ((properties & PROPERTY_AFFINE) != 0)
+ return determinantAffine();
+ return (m00 * m11 - m01 * m10) * (m22 * m33 - m23 * m32)
+ + (m02 * m10 - m00 * m12) * (m21 * m33 - m23 * m31)
+ + (m00 * m13 - m03 * m10) * (m21 * m32 - m22 * m31)
+ + (m01 * m12 - m02 * m11) * (m20 * m33 - m23 * m30)
+ + (m03 * m11 - m01 * m13) * (m20 * m32 - m22 * m30)
+ + (m02 * m13 - m03 * m12) * (m20 * m31 - m21 * m30);
+ }
+
+ public double determinant3x3() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ public double determinantAffine() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * If this
matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing,
+ * and thus its last row is equal to (0, 0, 0, 1)
, then {@link #invertAffine()} can be used instead of this method.
+ *
+ * @see #invertAffine()
+ *
+ * @return this
+ */
+ public Matrix4d invert() {
+ return invert(this);
+ }
+
+ public Matrix4d invert(Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return invertTranslation(dest);
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return invertOrthonormal(dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return invertAffine(dest);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return invertPerspective(dest);
+ return invertGeneric(dest);
+ }
+ private Matrix4d invertTranslation(Matrix4d dest) {
+ if (dest != this)
+ dest.set(this);
+ dest._m30(-m30)
+ ._m31(-m31)
+ ._m32(-m32)
+ ._properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+ private Matrix4d invertOrthonormal(Matrix4d dest) {
+ double nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
+ double nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
+ double nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
+ double m01 = this.m01;
+ double m02 = this.m02;
+ double m12 = this.m12;
+ dest._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m03(0.0)
+ ._m10(m01)
+ ._m11(m11)
+ ._m12(m21)
+ ._m13(0.0)
+ ._m20(m02)
+ ._m21(m12)
+ ._m22(m22)
+ ._m23(0.0)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(1.0)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+ private Matrix4d invertGeneric(Matrix4d dest) {
+ if (this != dest)
+ return invertGenericNonThis(dest);
+ return invertGenericThis(dest);
+ }
+ private Matrix4d invertGenericNonThis(Matrix4d dest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double c = m00 * m13 - m03 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double e = m01 * m13 - m03 * m11;
+ double f = m02 * m13 - m03 * m12;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double i = m20 * m33 - m23 * m30;
+ double j = m21 * m32 - m22 * m31;
+ double k = m21 * m33 - m23 * m31;
+ double l = m22 * m33 - m23 * m32;
+ double det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0 / det;
+ return dest
+ ._m00(Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det)
+ ._m01(Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det)
+ ._m02(Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det)
+ ._m03(Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det)
+ ._m10(Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det)
+ ._m11(Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det)
+ ._m12(Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det)
+ ._m13(Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det)
+ ._m20(Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det)
+ ._m21(Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det)
+ ._m22(Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det)
+ ._m23(Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det)
+ ._m30(Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det)
+ ._m31(Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det)
+ ._m32(Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det)
+ ._m33(Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det)
+ ._properties(0);
+ }
+ private Matrix4d invertGenericThis(Matrix4d dest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double c = m00 * m13 - m03 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double e = m01 * m13 - m03 * m11;
+ double f = m02 * m13 - m03 * m12;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double i = m20 * m33 - m23 * m30;
+ double j = m21 * m32 - m22 * m31;
+ double k = m21 * m33 - m23 * m31;
+ double l = m22 * m33 - m23 * m32;
+ double det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0 / det;
+ double nm00 = Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det;
+ double nm01 = Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det;
+ double nm02 = Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det;
+ double nm03 = Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det;
+ double nm10 = Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det;
+ double nm11 = Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det;
+ double nm12 = Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det;
+ double nm13 = Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det;
+ double nm20 = Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det;
+ double nm21 = Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det;
+ double nm22 = Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det;
+ double nm23 = Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det;
+ double nm30 = Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det;
+ double nm31 = Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det;
+ double nm32 = Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det;
+ double nm33 = Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ public Matrix4d invertPerspective(Matrix4d dest) {
+ double a = 1.0 / (m00 * m11);
+ double l = -1.0 / (m23 * m32);
+ dest.set(m11 * a, 0, 0, 0,
+ 0, m00 * a, 0, 0,
+ 0, 0, 0, -m23 * l,
+ 0, 0, -m32 * l, m22 * l);
+ return dest;
+ }
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(double, double, double, double) perspective()} methods
+ * or via {@link #setPerspective(double, double, double, double) setPerspective()}, that is, if this
is a symmetrical perspective frustum transformation,
+ * then this method builds the inverse of this
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix when being obtained via {@link #perspective(double, double, double, double) perspective()}.
+ *
+ * @see #perspective(double, double, double, double)
+ *
+ * @return this
+ */
+ public Matrix4d invertPerspective() {
+ return invertPerspective(this);
+ }
+
+ public Matrix4d invertFrustum(Matrix4d dest) {
+ double invM00 = 1.0 / m00;
+ double invM11 = 1.0 / m11;
+ double invM23 = 1.0 / m23;
+ double invM32 = 1.0 / m32;
+ dest.set(invM00, 0, 0, 0,
+ 0, invM11, 0, 0,
+ 0, 0, 0, invM32,
+ -m20 * invM00 * invM23, -m21 * invM11 * invM23, invM23, -m22 * invM23 * invM32);
+ return dest;
+ }
+
+ /**
+ * If this
is an arbitrary perspective projection matrix obtained via one of the {@link #frustum(double, double, double, double, double, double) frustum()} methods
+ * or via {@link #setFrustum(double, double, double, double, double, double) setFrustum()},
+ * then this method builds the inverse of this
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix.
+ *
+ * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(double, double, double, double) perspective()}, then
+ * {@link #invertPerspective()} should be used instead.
+ *
+ * @see #frustum(double, double, double, double, double, double)
+ * @see #invertPerspective()
+ *
+ * @return this
+ */
+ public Matrix4d invertFrustum() {
+ return invertFrustum(this);
+ }
+
+ public Matrix4d invertOrtho(Matrix4d dest) {
+ double invM00 = 1.0 / m00;
+ double invM11 = 1.0 / m11;
+ double invM22 = 1.0 / m22;
+ dest.set(invM00, 0, 0, 0,
+ 0, invM11, 0, 0,
+ 0, 0, invM22, 0,
+ -m30 * invM00, -m31 * invM11, -m32 * invM22, 1)
+ ._properties(PROPERTY_AFFINE | (this.properties & PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Invert this
orthographic projection matrix.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @return this
+ */
+ public Matrix4d invertOrtho() {
+ return invertOrtho(this);
+ }
+
+ public Matrix4d invertPerspectiveView(Matrix4dc view, Matrix4d dest) {
+ double a = 1.0 / (m00 * m11);
+ double l = -1.0 / (m23 * m32);
+ double pm00 = m11 * a;
+ double pm11 = m00 * a;
+ double pm23 = -m23 * l;
+ double pm32 = -m32 * l;
+ double pm33 = m22 * l;
+ double vm30 = -view.m00() * view.m30() - view.m01() * view.m31() - view.m02() * view.m32();
+ double vm31 = -view.m10() * view.m30() - view.m11() * view.m31() - view.m12() * view.m32();
+ double vm32 = -view.m20() * view.m30() - view.m21() * view.m31() - view.m22() * view.m32();
+ double nm10 = view.m01() * pm11;
+ double nm30 = view.m02() * pm32 + vm30 * pm33;
+ double nm31 = view.m12() * pm32 + vm31 * pm33;
+ double nm32 = view.m22() * pm32 + vm32 * pm33;
+ return dest
+ ._m00(view.m00() * pm00)
+ ._m01(view.m10() * pm00)
+ ._m02(view.m20() * pm00)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(view.m11() * pm11)
+ ._m12(view.m21() * pm11)
+ ._m13(0.0)
+ ._m20(vm30 * pm23)
+ ._m21(vm31 * pm23)
+ ._m22(vm32 * pm23)
+ ._m23(pm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(pm33)
+ ._properties(0);
+ }
+
+ public Matrix4d invertPerspectiveView(Matrix4x3dc view, Matrix4d dest) {
+ double a = 1.0 / (m00 * m11);
+ double l = -1.0 / (m23 * m32);
+ double pm00 = m11 * a;
+ double pm11 = m00 * a;
+ double pm23 = -m23 * l;
+ double pm32 = -m32 * l;
+ double pm33 = m22 * l;
+ double vm30 = -view.m00() * view.m30() - view.m01() * view.m31() - view.m02() * view.m32();
+ double vm31 = -view.m10() * view.m30() - view.m11() * view.m31() - view.m12() * view.m32();
+ double vm32 = -view.m20() * view.m30() - view.m21() * view.m31() - view.m22() * view.m32();
+ return dest
+ ._m00(view.m00() * pm00)
+ ._m01(view.m10() * pm00)
+ ._m02(view.m20() * pm00)
+ ._m03(0.0)
+ ._m10(view.m01() * pm11)
+ ._m11(view.m11() * pm11)
+ ._m12(view.m21() * pm11)
+ ._m13(0.0)
+ ._m20(vm30 * pm23)
+ ._m21(vm31 * pm23)
+ ._m22(vm32 * pm23)
+ ._m23(pm23)
+ ._m30(view.m02() * pm32 + vm30 * pm33)
+ ._m31(view.m12() * pm32 + vm31 * pm33)
+ ._m32(view.m22() * pm32 + vm32 * pm33)
+ ._m33(pm33)
+ ._properties(0);
+ }
+
+ public Matrix4d invertAffine(Matrix4d dest) {
+ double m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
+ double m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
+ double s = 1.0 / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20);
+ double m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
+ double m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
+ double m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
+ double m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
+ double nm00 = (m11m22 - m12m21) * s;
+ double nm01 = (m21m02 - m22m01) * s;
+ double nm02 = (m12m01 - m11m02) * s;
+ double nm10 = (m12m20 - m10m22) * s;
+ double nm11 = (m22m00 - m20m02) * s;
+ double nm12 = (m10m02 - m12m00) * s;
+ double nm20 = (m10m21 - m11m20) * s;
+ double nm21 = (m20m01 - m21m00) * s;
+ double nm22 = (m11m00 - m10m01) * s;
+ double nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s;
+ double nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
+ double nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(0.0)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(1.0)
+ ._properties(PROPERTY_AFFINE);
+ return dest;
+ }
+
+ /**
+ * Invert this matrix by assuming that it is an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
).
+ *
+ * @return this
+ */
+ public Matrix4d invertAffine() {
+ return invertAffine(this);
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this
+ */
+ public Matrix4d transpose() {
+ return transpose(this);
+ }
+
+ public Matrix4d transpose(Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if (this != dest)
+ return transposeNonThisGeneric(dest);
+ return transposeThisGeneric(dest);
+ }
+ private Matrix4d transposeNonThisGeneric(Matrix4d dest) {
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m03(m30)
+ ._m10(m01)
+ ._m11(m11)
+ ._m12(m21)
+ ._m13(m31)
+ ._m20(m02)
+ ._m21(m12)
+ ._m22(m22)
+ ._m23(m32)
+ ._m30(m03)
+ ._m31(m13)
+ ._m32(m23)
+ ._m33(m33)
+ ._properties(0);
+ }
+ private Matrix4d transposeThisGeneric(Matrix4d dest) {
+ double nm10 = m01;
+ double nm20 = m02;
+ double nm21 = m12;
+ double nm30 = m03;
+ double nm31 = m13;
+ double nm32 = m23;
+ return dest
+ ._m01(m10)
+ ._m02(m20)
+ ._m03(m30)
+ ._m10(nm10)
+ ._m12(m21)
+ ._m13(m31)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m23(m32)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._properties(0);
+ }
+
+ /**
+ * Transpose only the upper left 3x3 submatrix of this matrix.
+ *
+ * All other matrix elements are left unchanged.
+ *
+ * @return this
+ */
+ public Matrix4d transpose3x3() {
+ return transpose3x3(this);
+ }
+
+ public Matrix4d transpose3x3(Matrix4d dest) {
+ double nm10 = m01, nm20 = m02, nm21 = m12;
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m10(nm10)
+ ._m11(m11)
+ ._m12(m21)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(m22)
+ ._properties(this.properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ public Matrix3d transpose3x3(Matrix3d dest) {
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m10(m01)
+ ._m11(m11)
+ ._m12(m21)
+ ._m20(m02)
+ ._m21(m12)
+ ._m22(m22);
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4d translation(double x, double y, double z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ return this.
+ _m30(x).
+ _m31(y).
+ _m32(z).
+ _m33(1.0).
+ _properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * @param offset
+ * the offsets in x, y and z to translate
+ * @return this
+ */
+ public Matrix4d translation(Vector3fc offset) {
+ return translation(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * @param offset
+ * the offsets in x, y and z to translate
+ * @return this
+ */
+ public Matrix4d translation(Vector3dc offset) {
+ return translation(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the given values (x, y, z)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(double, double, double)}.
+ * To apply a translation, use {@link #translate(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ * @see #translate(double, double, double)
+ *
+ * @param x
+ * the units to translate in x
+ * @param y
+ * the units to translate in y
+ * @param z
+ * the units to translate in z
+ * @return this
+ */
+ public Matrix4d setTranslation(double x, double y, double z) {
+ _m30(x).
+ _m31(y).
+ _m32(z).
+ properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY);
+ return this;
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the given values (xyz.x, xyz.y, xyz.z)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(Vector3dc)}.
+ * To apply a translation, use {@link #translate(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ * @see #translate(Vector3dc)
+ *
+ * @param xyz
+ * the units to translate in (x, y, z)
+ * @return this
+ */
+ public Matrix4d setTranslation(Vector3dc xyz) {
+ return setTranslation(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ public Vector3d getTranslation(Vector3d dest) {
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ return dest;
+ }
+
+ public Vector3d getScale(Vector3d dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + " " + Runtime.format(m30, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + " " + Runtime.format(m31, formatter) + "\n"
+ + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + " " + Runtime.format(m32, formatter) + "\n"
+ + Runtime.format(m03, formatter) + " " + Runtime.format(m13, formatter) + " " + Runtime.format(m23, formatter) + " " + Runtime.format(m33, formatter) + "\n";
+ }
+
+ public Matrix4d get(Matrix4d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4x3d get4x3(Matrix4x3d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3d get3x3(Matrix3d dest) {
+ return dest.set(this);
+ }
+
+ public Quaternionf getUnnormalizedRotation(Quaternionf dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaternionf getNormalizedRotation(Quaternionf dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaterniond getNormalizedRotation(Quaterniond dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public DoubleBuffer get(DoubleBuffer dest) {
+ MemUtil.INSTANCE.put(this, dest.position(), dest);
+ return dest;
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer dest) {
+ MemUtil.INSTANCE.put(this, index, dest);
+ return dest;
+ }
+
+ public FloatBuffer get(FloatBuffer dest) {
+ MemUtil.INSTANCE.putf(this, dest.position(), dest);
+ return dest;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer dest) {
+ MemUtil.INSTANCE.putf(this, index, dest);
+ return dest;
+ }
+
+ public ByteBuffer get(ByteBuffer dest) {
+ MemUtil.INSTANCE.put(this, dest.position(), dest);
+ return dest;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer dest) {
+ MemUtil.INSTANCE.put(this, index, dest);
+ return dest;
+ }
+
+ public ByteBuffer getFloats(ByteBuffer dest) {
+ MemUtil.INSTANCE.putf(this, dest.position(), dest);
+ return dest;
+ }
+
+ public ByteBuffer getFloats(int index, ByteBuffer dest) {
+ MemUtil.INSTANCE.putf(this, index, dest);
+ return dest;
+ }
+ public Matrix4dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public double[] get(double[] dest, int offset) {
+ dest[offset+0] = m00;
+ dest[offset+1] = m01;
+ dest[offset+2] = m02;
+ dest[offset+3] = m03;
+ dest[offset+4] = m10;
+ dest[offset+5] = m11;
+ dest[offset+6] = m12;
+ dest[offset+7] = m13;
+ dest[offset+8] = m20;
+ dest[offset+9] = m21;
+ dest[offset+10] = m22;
+ dest[offset+11] = m23;
+ dest[offset+12] = m30;
+ dest[offset+13] = m31;
+ dest[offset+14] = m32;
+ dest[offset+15] = m33;
+ return dest;
+ }
+
+ public double[] get(double[] dest) {
+ return get(dest, 0);
+ }
+
+ public float[] get(float[] dest, int offset) {
+ dest[offset+0] = (float)m00;
+ dest[offset+1] = (float)m01;
+ dest[offset+2] = (float)m02;
+ dest[offset+3] = (float)m03;
+ dest[offset+4] = (float)m10;
+ dest[offset+5] = (float)m11;
+ dest[offset+6] = (float)m12;
+ dest[offset+7] = (float)m13;
+ dest[offset+8] = (float)m20;
+ dest[offset+9] = (float)m21;
+ dest[offset+10] = (float)m22;
+ dest[offset+11] = (float)m23;
+ dest[offset+12] = (float)m30;
+ dest[offset+13] = (float)m31;
+ dest[offset+14] = (float)m32;
+ dest[offset+15] = (float)m33;
+ return dest;
+ }
+
+ public float[] get(float[] dest) {
+ return get(dest, 0);
+ }
+
+ public DoubleBuffer getTransposed(DoubleBuffer dest) {
+ MemUtil.INSTANCE.putTransposed(this, dest.position(), dest);
+ return dest;
+ }
+
+ public DoubleBuffer getTransposed(int index, DoubleBuffer dest) {
+ MemUtil.INSTANCE.putTransposed(this, index, dest);
+ return dest;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer dest) {
+ MemUtil.INSTANCE.putTransposed(this, dest.position(), dest);
+ return dest;
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer dest) {
+ MemUtil.INSTANCE.putTransposed(this, index, dest);
+ return dest;
+ }
+
+ public DoubleBuffer get4x3Transposed(DoubleBuffer dest) {
+ MemUtil.INSTANCE.put4x3Transposed(this, dest.position(), dest);
+ return dest;
+ }
+
+ public DoubleBuffer get4x3Transposed(int index, DoubleBuffer dest) {
+ MemUtil.INSTANCE.put4x3Transposed(this, index, dest);
+ return dest;
+ }
+
+ public ByteBuffer get4x3Transposed(ByteBuffer dest) {
+ MemUtil.INSTANCE.put4x3Transposed(this, dest.position(), dest);
+ return dest;
+ }
+
+ public ByteBuffer get4x3Transposed(int index, ByteBuffer dest) {
+ MemUtil.INSTANCE.put4x3Transposed(this, index, dest);
+ return dest;
+ }
+
+ /**
+ * Set all the values within this matrix to 0.
+ *
+ * @return this
+ */
+ public Matrix4d zero() {
+ return
+ _m00(0.0).
+ _m01(0.0).
+ _m02(0.0).
+ _m03(0.0).
+ _m10(0.0).
+ _m11(0.0).
+ _m12(0.0).
+ _m13(0.0).
+ _m20(0.0).
+ _m21(0.0).
+ _m22(0.0).
+ _m23(0.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m32(0.0).
+ _m33(0.0).
+ _properties(0);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(double) scale()} instead.
+ *
+ * @see #scale(double)
+ *
+ * @param factor
+ * the scale factor in x, y and z
+ * @return this
+ */
+ public Matrix4d scaling(double factor) {
+ return scaling(factor, factor, factor);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @param z
+ * the scale in z
+ * @return this
+ */
+ public Matrix4d scaling(double x, double y, double z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ identity();
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ _m00(x).
+ _m11(y).
+ _m22(z).
+ properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by
+ * xyz.x
, xyz.y
and xyz.z
, respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector3dc) scale()} instead.
+ *
+ * @see #scale(Vector3dc)
+ *
+ * @param xyz
+ * the scale in x, y and z, respectively
+ * @return this
+ */
+ public Matrix4d scaling(Vector3dc xyz) {
+ return scaling(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * From Wikipedia
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-coordinate of the axis to rotate about
+ * @param y
+ * the y-coordinate of the axis to rotate about
+ * @param z
+ * the z-coordinate of the axis to rotate about
+ * @return this
+ */
+ public Matrix4d rotation(double angle, double x, double y, double z) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotationX(x * angle);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotationY(y * angle);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotationZ(z * angle);
+ return rotationInternal(angle, x, y, z);
+ }
+ private Matrix4d rotationInternal(double angle, double x, double y, double z) {
+ double sin = Math.sin(angle);
+ double cos = Math.cosFromSin(sin, angle);
+ double C = 1.0 - cos;
+ double xy = x * y, xz = x * z, yz = y * z;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ _m00(cos + x * x * C).
+ _m10(xy * C - z * sin).
+ _m20(xz * C + y * sin).
+ _m01(xy * C + z * sin).
+ _m11(cos + y * y * C).
+ _m21(yz * C - x * sin).
+ _m02(xz * C - y * sin).
+ _m12(yz * C + x * sin).
+ _m22(cos + z * z * C).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4d rotationX(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ _m11(cos).
+ _m12(sin).
+ _m21(-sin).
+ _m22(cos).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4d rotationY(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ _m00(cos).
+ _m02(-sin).
+ _m20(sin).
+ _m22(cos).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4d rotationZ(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ _m00(cos).
+ _m01(sin).
+ _m10(-sin).
+ _m11(cos).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis to align the local +X
towards (dirX, dirY)
.
+ *
+ * The vector (dirX, dirY)
must be a unit vector.
+ *
+ * @param dirX
+ * the x component of the normalized direction
+ * @param dirY
+ * the y component of the normalized direction
+ * @return this
+ */
+ public Matrix4d rotationTowardsXY(double dirX, double dirY) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ this.m00 = dirY;
+ this.m01 = dirX;
+ this.m10 = -dirX;
+ this.m11 = dirY;
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d rotationXYZ(double angleX, double angleY, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+
+ // rotateX
+ double nm11 = cosX;
+ double nm12 = sinX;
+ double nm21 = m_sinX;
+ double nm22 = cosX;
+ // rotateY
+ double nm00 = cosY;
+ double nm01 = nm21 * m_sinY;
+ double nm02 = nm22 * m_sinY;
+ _m20(sinY).
+ _m21(nm21 * cosY).
+ _m22(nm22 * cosY).
+ // rotateZ
+ _m00(nm00 * cosZ).
+ _m01(nm01 * cosZ + nm11 * sinZ).
+ _m02(nm02 * cosZ + nm12 * sinZ).
+ _m10(nm00 * m_sinZ).
+ _m11(nm01 * m_sinZ + nm11 * cosZ).
+ _m12(nm02 * m_sinZ + nm12 * cosZ).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4d rotationZYX(double angleZ, double angleY, double angleX) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+
+ // rotateZ
+ double nm00 = cosZ;
+ double nm01 = sinZ;
+ double nm10 = m_sinZ;
+ double nm11 = cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY;
+ double nm21 = nm01 * sinY;
+ double nm22 = cosY;
+ _m00(nm00 * cosY).
+ _m01(nm01 * cosY).
+ _m02(m_sinY).
+ // rotateX
+ _m10(nm10 * cosX + nm20 * sinX).
+ _m11(nm11 * cosX + nm21 * sinX).
+ _m12(nm22 * sinX).
+ _m20(nm10 * m_sinX + nm20 * cosX).
+ _m21(nm11 * m_sinX + nm21 * cosX).
+ _m22(nm22 * cosX).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d rotationYXZ(double angleY, double angleX, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm00 = cosY;
+ double nm02 = m_sinY;
+ double nm20 = sinY;
+ double nm22 = cosY;
+ // rotateX
+ double nm10 = nm20 * sinX;
+ double nm11 = cosX;
+ double nm12 = nm22 * sinX;
+ _m20(nm20 * cosX).
+ _m21(m_sinX).
+ _m22(nm22 * cosX).
+ _m23(0.0).
+ // rotateZ
+ _m00(nm00 * cosZ + nm10 * sinZ).
+ _m01(nm11 * sinZ).
+ _m02(nm02 * cosZ + nm12 * sinZ).
+ _m03(0.0).
+ _m10(nm00 * m_sinZ + nm10 * cosZ).
+ _m11(nm11 * cosZ).
+ _m12(nm02 * m_sinZ + nm12 * cosZ).
+ _m13(0.0).
+ // set last column to identity
+ _m30(0.0).
+ _m31(0.0).
+ _m32(0.0).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set only the upper left 3x3 submatrix of this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d setRotationXYZ(double angleX, double angleY, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm11 = cosX;
+ double nm12 = sinX;
+ double nm21 = m_sinX;
+ double nm22 = cosX;
+ // rotateY
+ double nm00 = cosY;
+ double nm01 = nm21 * m_sinY;
+ double nm02 = nm22 * m_sinY;
+ _m20(sinY).
+ _m21(nm21 * cosY).
+ _m22(nm22 * cosY).
+ // rotateZ
+ _m00(nm00 * cosZ).
+ _m01(nm01 * cosZ + nm11 * sinZ).
+ _m02(nm02 * cosZ + nm12 * sinZ).
+ _m10(nm00 * m_sinZ).
+ _m11(nm01 * m_sinZ + nm11 * cosZ).
+ _m12(nm02 * m_sinZ + nm12 * cosZ).
+ properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set only the upper left 3x3 submatrix of this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4d setRotationZYX(double angleZ, double angleY, double angleX) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = cosZ;
+ double nm01 = sinZ;
+ double nm10 = m_sinZ;
+ double nm11 = cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY;
+ double nm21 = nm01 * sinY;
+ double nm22 = cosY;
+ _m00(nm00 * cosY).
+ _m01(nm01 * cosY).
+ _m02(m_sinY).
+ // rotateX
+ _m10(nm10 * cosX + nm20 * sinX).
+ _m11(nm11 * cosX + nm21 * sinX).
+ _m12(nm22 * sinX).
+ _m20(nm10 * m_sinX + nm20 * cosX).
+ _m21(nm11 * m_sinX + nm21 * cosX).
+ _m22(nm22 * cosX).
+ properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set only the upper left 3x3 submatrix of this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d setRotationYXZ(double angleY, double angleX, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm00 = cosY;
+ double nm02 = m_sinY;
+ double nm20 = sinY;
+ double nm22 = cosY;
+ // rotateX
+ double nm10 = nm20 * sinX;
+ double nm11 = cosX;
+ double nm12 = nm22 * sinX;
+ _m20(nm20 * cosX).
+ _m21(m_sinX).
+ _m22(nm22 * cosX).
+ // rotateZ
+ _m00(nm00 * cosZ + nm10 * sinZ).
+ _m01(nm11 * sinZ).
+ _m02(nm02 * cosZ + nm12 * sinZ).
+ _m10(nm00 * m_sinZ + nm10 * cosZ).
+ _m11(nm11 * cosZ).
+ _m12(nm02 * m_sinZ + nm12 * cosZ).
+ properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about
+ * @return this
+ */
+ public Matrix4d rotation(double angle, Vector3dc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about
+ * @return this
+ */
+ public Matrix4d rotation(double angle, Vector3fc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ public Vector4d transform(Vector4d v) {
+ return v.mul(this);
+ }
+
+ public Vector4d transform(Vector4dc v, Vector4d dest) {
+ return v.mul(this, dest);
+ }
+
+ public Vector4d transform(double x, double y, double z, double w, Vector4d dest) {
+ return dest.set(m00 * x + m10 * y + m20 * z + m30 * w,
+ m01 * x + m11 * y + m21 * z + m31 * w,
+ m02 * x + m12 * y + m22 * z + m32 * w,
+ m03 * x + m13 * y + m23 * z + m33 * w);
+ }
+
+ public Vector4d transformTranspose(Vector4d v) {
+ return v.mulTranspose(this);
+ }
+ public Vector4d transformTranspose(Vector4dc v, Vector4d dest) {
+ return v.mulTranspose(this, dest);
+ }
+ public Vector4d transformTranspose(double x, double y, double z, double w, Vector4d dest) {
+ return dest.set(x, y, z, w).mulTranspose(this);
+ }
+
+ public Vector4d transformProject(Vector4d v) {
+ return v.mulProject(this);
+ }
+
+ public Vector4d transformProject(Vector4dc v, Vector4d dest) {
+ return v.mulProject(this, dest);
+ }
+
+ public Vector4d transformProject(double x, double y, double z, double w, Vector4d dest) {
+ double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33 * w);
+ return dest.set((m00 * x + m10 * y + m20 * z + m30 * w) * invW,
+ (m01 * x + m11 * y + m21 * z + m31 * w) * invW,
+ (m02 * x + m12 * y + m22 * z + m32 * w) * invW,
+ 1.0);
+ }
+
+ public Vector3d transformProject(Vector3d v) {
+ return v.mulProject(this);
+ }
+
+ public Vector3d transformProject(Vector3dc v, Vector3d dest) {
+ return v.mulProject(this, dest);
+ }
+
+ public Vector3d transformProject(double x, double y, double z, Vector3d dest) {
+ double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33);
+ return dest.set((m00 * x + m10 * y + m20 * z + m30) * invW,
+ (m01 * x + m11 * y + m21 * z + m31) * invW,
+ (m02 * x + m12 * y + m22 * z + m32) * invW);
+ }
+
+ public Vector3d transformProject(Vector4dc v, Vector3d dest) {
+ return v.mulProject(this, dest);
+ }
+
+ public Vector3d transformProject(double x, double y, double z, double w, Vector3d dest) {
+ dest.x = x;
+ dest.y = y;
+ dest.z = z;
+ return dest.mulProject(this, w, dest);
+ }
+
+ public Vector3d transformPosition(Vector3d dest) {
+ return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z + m30,
+ m01 * dest.x + m11 * dest.y + m21 * dest.z + m31,
+ m02 * dest.x + m12 * dest.y + m22 * dest.z + m32);
+ }
+
+ public Vector3d transformPosition(Vector3dc v, Vector3d dest) {
+ return transformPosition(v.x(), v.y(), v.z(), dest);
+ }
+
+ public Vector3d transformPosition(double x, double y, double z, Vector3d dest) {
+ return dest.set(m00 * x + m10 * y + m20 * z + m30,
+ m01 * x + m11 * y + m21 * z + m31,
+ m02 * x + m12 * y + m22 * z + m32);
+ }
+
+ public Vector3d transformDirection(Vector3d dest) {
+ return dest.set(m00 * dest.x + m10 * dest.y + m20 * dest.z,
+ m01 * dest.x + m11 * dest.y + m21 * dest.z,
+ m02 * dest.x + m12 * dest.y + m22 * dest.z);
+ }
+
+ public Vector3d transformDirection(Vector3dc v, Vector3d dest) {
+ return dest.set(m00 * v.x() + m10 * v.y() + m20 * v.z(),
+ m01 * v.x() + m11 * v.y() + m21 * v.z(),
+ m02 * v.x() + m12 * v.y() + m22 * v.z());
+ }
+
+ public Vector3d transformDirection(double x, double y, double z, Vector3d dest) {
+ return dest.set(m00 * x + m10 * y + m20 * z,
+ m01 * x + m11 * y + m21 * z,
+ m02 * x + m12 * y + m22 * z);
+ }
+
+ public Vector3f transformDirection(Vector3f dest) {
+ return dest.mulDirection(this);
+ }
+
+ public Vector3f transformDirection(Vector3fc v, Vector3f dest) {
+ return v.mulDirection(this, dest);
+ }
+
+ public Vector3f transformDirection(double x, double y, double z, Vector3f dest) {
+ float rx = (float)(m00 * x + m10 * y + m20 * z);
+ float ry = (float)(m01 * x + m11 * y + m21 * z);
+ float rz = (float)(m02 * x + m12 * y + m22 * z);
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector4d transformAffine(Vector4d dest) {
+ return dest.mulAffine(this, dest);
+ }
+
+ public Vector4d transformAffine(Vector4dc v, Vector4d dest) {
+ return transformAffine(v.x(), v.y(), v.z(), v.w(), dest);
+ }
+
+ public Vector4d transformAffine(double x, double y, double z, double w, Vector4d dest) {
+ double rx = m00 * x + m10 * y + m20 * z + m30 * w;
+ double ry = m01 * x + m11 * y + m21 * z + m31 * w;
+ double rz = m02 * x + m12 * y + m22 * z + m32 * w;
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = w;
+ return dest;
+ }
+
+ /**
+ * Set the upper left 3x3 submatrix of this {@link Matrix4d} to the given {@link Matrix3dc} and don't change the other elements.
+ *
+ * @param mat
+ * the 3x3 matrix
+ * @return this
+ */
+ public Matrix4d set3x3(Matrix3dc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+
+ public Matrix4d scale(Vector3dc xyz, Matrix4d dest) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @return this
+ */
+ public Matrix4d scale(Vector3dc xyz) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), this);
+ }
+
+ public Matrix4d scale(double x, double y, double z, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ return scaleGeneric(x, y, z, dest);
+ }
+ private Matrix4d scaleGeneric(double x, double y, double z, Matrix4d dest) {
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ dest._m00(m00 * x)
+ ._m01(m01 * x)
+ ._m02(m02 * x)
+ ._m03(m03 * x)
+ ._m10(m10 * y)
+ ._m11(m11 * y)
+ ._m12(m12 * y)
+ ._m13(m13 * y)
+ ._m20(m20 * z)
+ ._m21(m21 * z)
+ ._m22(m22 * z)
+ ._m23(m23 * z)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties
+ & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4d scale(double x, double y, double z) {
+ return scale(x, y, z, this);
+ }
+
+ public Matrix4d scale(double xyz, Matrix4d dest) {
+ return scale(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, double)
+ *
+ * @param xyz
+ * the factor for all components
+ * @return this
+ */
+ public Matrix4d scale(double xyz) {
+ return scale(xyz, xyz, xyz);
+ }
+
+ public Matrix4d scaleXY(double x, double y, Matrix4d dest) {
+ return scale(x, y, 1.0, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the X axis by x
and the Y axis by y
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix4d scaleXY(double x, double y) {
+ return scale(x, y, 1.0);
+ }
+
+ public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4d dest) {
+ double nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ double nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ double nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ double nm33 = m03 * ox + m13 * oy + m23 * oz + m33;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return dest
+ ._m00(m00 * sx)
+ ._m01(m01 * sx)
+ ._m02(m02 * sx)
+ ._m03(m03 * sx)
+ ._m10(m10 * sy)
+ ._m11(m11 * sy)
+ ._m12(m12 * sy)
+ ._m13(m13 * sy)
+ ._m20(m20 * sz)
+ ._m21(m21 * sz)
+ ._m22(m22 * sz)
+ ._m23(m23 * sz)
+ ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30)
+ ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31)
+ ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32)
+ ._m33(-dest.m03 * ox - dest.m13 * oy - dest.m23 * oz + nm33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) {
+ return scaleAround(sx, sy, sz, ox, oy, oz, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4d scaleAround(double factor, double ox, double oy, double oz) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, this);
+ }
+
+ public Matrix4d scaleAround(double factor, double ox, double oy, double oz, Matrix4d dest) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, dest);
+ }
+
+ public Matrix4d scaleLocal(double x, double y, double z, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ return scaleLocalGeneric(x, y, z, dest);
+ }
+ private Matrix4d scaleLocalGeneric(double x, double y, double z, Matrix4d dest) {
+ double nm00 = x * m00;
+ double nm01 = y * m01;
+ double nm02 = z * m02;
+ double nm10 = x * m10;
+ double nm11 = y * m11;
+ double nm12 = z * m12;
+ double nm20 = x * m20;
+ double nm21 = y * m21;
+ double nm22 = z * m22;
+ double nm30 = x * m30;
+ double nm31 = y * m31;
+ double nm32 = z * m32;
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ return dest;
+ }
+
+ public Matrix4d scaleLocal(double xyz, Matrix4d dest) {
+ return scaleLocal(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given xyz factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param xyz
+ * the factor of the x, y and z component
+ * @return this
+ */
+ public Matrix4d scaleLocal(double xyz) {
+ return scaleLocal(xyz, this);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4d scaleLocal(double x, double y, double z) {
+ return scaleLocal(x, y, z, this);
+ }
+
+ public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4d dest) {
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ dest._m00(sx * (m00 - ox * m03) + ox * m03)
+ ._m01(sy * (m01 - oy * m03) + oy * m03)
+ ._m02(sz * (m02 - oz * m03) + oz * m03)
+ ._m03(m03)
+ ._m10(sx * (m10 - ox * m13) + ox * m13)
+ ._m11(sy * (m11 - oy * m13) + oy * m13)
+ ._m12(sz * (m12 - oz * m13) + oz * m13)
+ ._m13(m13)
+ ._m20(sx * (m20 - ox * m23) + ox * m23)
+ ._m21(sy * (m21 - oy * m23) + oy * m23)
+ ._m22(sz * (m22 - oz * m23) + oz * m23)
+ ._m23(m23)
+ ._m30(sx * (m30 - ox * m33) + ox * m33)
+ ._m31(sy * (m31 - oy * m33) + oy * m33)
+ ._m32(sz * (m32 - oz * m33) + oz * m33)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4d().translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz).mul(this, this)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz) {
+ return scaleAroundLocal(sx, sy, sz, ox, oy, oz, this);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4d().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, this)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz) {
+ return scaleAroundLocal(factor, factor, factor, ox, oy, oz, this);
+ }
+
+ public Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz, Matrix4d dest) {
+ return scaleAroundLocal(factor, factor, factor, ox, oy, oz, dest);
+ }
+
+ public Matrix4d rotate(double ang, double x, double y, double z, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(ang, x, y, z);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(ang, x, y, z, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAffine(ang, x, y, z, dest);
+ return rotateGeneric(ang, x, y, z, dest);
+ }
+ private Matrix4d rotateGeneric(double ang, double x, double y, double z, Matrix4d dest) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateX(x * ang, dest);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateY(y * ang, dest);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateZ(z * ang, dest);
+ return rotateGenericInternal(ang, x, y, z, dest);
+ }
+ private Matrix4d rotateGenericInternal(double ang, double x, double y, double z, Matrix4d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double rm00 = xx * C + c;
+ double rm01 = xy * C + z * s;
+ double rm02 = xz * C - y * s;
+ double rm10 = xy * C - z * s;
+ double rm11 = yy * C + c;
+ double rm12 = yz * C + x * s;
+ double rm20 = xz * C + y * s;
+ double rm21 = yz * C - x * s;
+ double rm22 = zz * C + c;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle is in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4d rotate(double ang, double x, double y, double z) {
+ return rotate(ang, x, y, z, this);
+ }
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateTranslation(double ang, double x, double y, double z, Matrix4d dest) {
+ double tx = m30, ty = m31, tz = m32;
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return dest.rotationX(x * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return dest.rotationY(y * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return dest.rotationZ(z * ang).setTranslation(tx, ty, tz);
+ return rotateTranslationInternal(ang, x, y, z, dest);
+ }
+ private Matrix4d rotateTranslationInternal(double ang, double x, double y, double z, Matrix4d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double rm00 = xx * C + c;
+ double rm01 = xy * C + z * s;
+ double rm02 = xz * C - y * s;
+ double rm10 = xy * C - z * s;
+ double rm11 = yy * C + c;
+ double rm12 = yz * C + x * s;
+ double rm20 = xz * C + y * s;
+ double rm21 = yz * C - x * s;
+ double rm22 = zz * C + c;
+ double nm00 = rm00;
+ double nm01 = rm01;
+ double nm02 = rm02;
+ double nm10 = rm10;
+ double nm11 = rm11;
+ double nm12 = rm12;
+ // set non-dependent values directly
+ dest._m20(rm20)
+ ._m21(rm21)
+ ._m22(rm22)
+ // set other values
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateAffine(double ang, double x, double y, double z, Matrix4d dest) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateX(x * ang, dest);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateY(y * ang, dest);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateZ(z * ang, dest);
+ return rotateAffineInternal(ang, x, y, z, dest);
+ }
+ private Matrix4d rotateAffineInternal(double ang, double x, double y, double z, Matrix4d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double rm00 = xx * C + c;
+ double rm01 = xy * C + z * s;
+ double rm02 = xz * C - y * s;
+ double rm10 = xy * C - z * s;
+ double rm11 = yy * C + c;
+ double rm12 = yz * C + x * s;
+ double rm20 = xz * C + y * s;
+ double rm21 = yz * C - x * s;
+ double rm22 = zz * C + c;
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0)
+ // set other values
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4d rotateAffine(double ang, double x, double y, double z) {
+ return rotateAffine(ang, x, y, z, this);
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaterniondc} to this matrix while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4d rotateAround(Quaterniondc quat, double ox, double oy, double oz) {
+ return rotateAround(quat, ox, oy, oz, this);
+ }
+
+ public Matrix4d rotateAroundAffine(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = -dzw + dxy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ double tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ double tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
+ ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
+ ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
+ ._m33(1.0)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ public Matrix4d rotateAround(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return rotationAround(quat, ox, oy, oz);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAroundAffine(quat, ox, oy, oz, this);
+ return rotateAroundGeneric(quat, ox, oy, oz, this);
+ }
+ private Matrix4d rotateAroundGeneric(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = -dzw + dxy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ double tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ double tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
+ ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
+ ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a transformation composed of a rotation of the specified {@link Quaterniondc} while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4d rotationAround(Quaterniondc quat, double ox, double oy, double oz) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ this._m20(dyw + dxz);
+ this._m21(dyz - dxw);
+ this._m22(z2 - y2 - x2 + w2);
+ this._m23(0.0);
+ this._m00(w2 + x2 - z2 - y2);
+ this._m01(dxy + dzw);
+ this._m02(dxz - dyw);
+ this._m03(0.0);
+ this._m10(-dzw + dxy);
+ this._m11(y2 - z2 + w2 - x2);
+ this._m12(dyz + dxw);
+ this._m13(0.0);
+ this._m30(-m00 * ox - m10 * oy - m20 * oz + ox);
+ this._m31(-m01 * ox - m11 * oy - m21 * oz + oy);
+ this._m32(-m02 * ox - m12 * oy - m22 * oz + oz);
+ this._m33(1.0);
+ this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateLocal(double ang, double x, double y, double z, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(ang, x, y, z);
+ return rotateLocalGeneric(ang, x, y, z, dest);
+ }
+ private Matrix4d rotateLocalGeneric(double ang, double x, double y, double z, Matrix4d dest) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateLocalX(x * ang, dest);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateLocalY(y * ang, dest);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateLocalZ(z * ang, dest);
+ return rotateLocalGenericInternal(ang, x, y, z, dest);
+ }
+ private Matrix4d rotateLocalGenericInternal(double ang, double x, double y, double z, Matrix4d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double lm00 = xx * C + c;
+ double lm01 = xy * C + z * s;
+ double lm02 = xz * C - y * s;
+ double lm10 = xy * C - z * s;
+ double lm11 = yy * C + c;
+ double lm12 = yz * C + x * s;
+ double lm20 = xz * C + y * s;
+ double lm21 = yz * C - x * s;
+ double lm22 = zz * C + c;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4d rotateLocal(double ang, double x, double y, double z) {
+ return rotateLocal(ang, x, y, z, this);
+ }
+
+ public Matrix4d rotateAroundLocal(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = xy + zw + zw + xy;
+ double lm02 = xz - yw + xz - yw;
+ double lm10 = -zw + xy - zw + xy;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = yz + yz + xw + xw;
+ double lm20 = yw + xz + xz + yw;
+ double lm21 = yz + yz - xw - xw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double tm00 = m00 - ox * m03;
+ double tm01 = m01 - oy * m03;
+ double tm02 = m02 - oz * m03;
+ double tm10 = m10 - ox * m13;
+ double tm11 = m11 - oy * m13;
+ double tm12 = m12 - oz * m13;
+ double tm20 = m20 - ox * m23;
+ double tm21 = m21 - oy * m23;
+ double tm22 = m22 - oz * m23;
+ double tm30 = m30 - ox * m33;
+ double tm31 = m31 - oy * m33;
+ double tm32 = m32 - oz * m33;
+ dest._m00(lm00 * tm00 + lm10 * tm01 + lm20 * tm02 + ox * m03)
+ ._m01(lm01 * tm00 + lm11 * tm01 + lm21 * tm02 + oy * m03)
+ ._m02(lm02 * tm00 + lm12 * tm01 + lm22 * tm02 + oz * m03)
+ ._m03(m03)
+ ._m10(lm00 * tm10 + lm10 * tm11 + lm20 * tm12 + ox * m13)
+ ._m11(lm01 * tm10 + lm11 * tm11 + lm21 * tm12 + oy * m13)
+ ._m12(lm02 * tm10 + lm12 * tm11 + lm22 * tm12 + oz * m13)
+ ._m13(m13)
+ ._m20(lm00 * tm20 + lm10 * tm21 + lm20 * tm22 + ox * m23)
+ ._m21(lm01 * tm20 + lm11 * tm21 + lm21 * tm22 + oy * m23)
+ ._m22(lm02 * tm20 + lm12 * tm21 + lm22 * tm22 + oz * m23)
+ ._m23(m23)
+ ._m30(lm00 * tm30 + lm10 * tm31 + lm20 * tm32 + ox * m33)
+ ._m31(lm01 * tm30 + lm11 * tm31 + lm21 * tm32 + oy * m33)
+ ._m32(lm02 * tm30 + lm12 * tm31 + lm22 * tm32 + oz * m33)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix while using (ox, oy, oz)
+ * as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * This method is equivalent to calling: translateLocal(-ox, -oy, -oz).rotateLocal(quat).translateLocal(ox, oy, oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4d rotateAroundLocal(Quaterniondc quat, double ox, double oy, double oz) {
+ return rotateAroundLocal(quat, ox, oy, oz, this);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4d translate(Vector3dc offset) {
+ return translate(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d translate(Vector3dc offset, Matrix4d dest) {
+ return translate(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4d translate(Vector3fc offset) {
+ return translate(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d translate(Vector3fc offset, Matrix4d dest) {
+ return translate(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d translate(double x, double y, double z, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.translation(x, y, z);
+ return translateGeneric(x, y, z, dest);
+ }
+ private Matrix4d translateGeneric(double x, double y, double z, Matrix4d dest) {
+ dest._m00(m00)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(m11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))))
+ ._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))))
+ ._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))))
+ ._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))))
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY));
+ return dest;
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4d translate(double x, double y, double z) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return translation(x, y, z);
+ this._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))));
+ this._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))));
+ this._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))));
+ this._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))));
+ this.properties &= ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY);
+ return this;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4d translateLocal(Vector3fc offset) {
+ return translateLocal(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d translateLocal(Vector3fc offset, Matrix4d dest) {
+ return translateLocal(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4d translateLocal(Vector3dc offset) {
+ return translateLocal(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d translateLocal(Vector3dc offset, Matrix4d dest) {
+ return translateLocal(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d translateLocal(double x, double y, double z, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.translation(x, y, z);
+ return translateLocalGeneric(x, y, z, dest);
+ }
+ private Matrix4d translateLocalGeneric(double x, double y, double z, Matrix4d dest) {
+ double nm00 = m00 + x * m03;
+ double nm01 = m01 + y * m03;
+ double nm02 = m02 + z * m03;
+ double nm10 = m10 + x * m13;
+ double nm11 = m11 + y * m13;
+ double nm12 = m12 + z * m13;
+ double nm20 = m20 + x * m23;
+ double nm21 = m21 + y * m23;
+ double nm22 = m22 + z * m23;
+ double nm30 = m30 + x * m33;
+ double nm31 = m31 + y * m33;
+ double nm32 = m32 + z * m33;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY));
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4d translateLocal(double x, double y, double z) {
+ return translateLocal(x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(double) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateLocalX(double ang, Matrix4d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm02 = sin * m01 + cos * m02;
+ double nm12 = sin * m11 + cos * m12;
+ double nm22 = sin * m21 + cos * m22;
+ double nm32 = sin * m31 + cos * m32;
+ dest
+ ._m00(m00)
+ ._m01(cos * m01 - sin * m02)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(cos * m11 - sin * m12)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(m20)
+ ._m21(cos * m21 - sin * m22)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(cos * m31 - sin * m32)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(double) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix4d rotateLocalX(double ang) {
+ return rotateLocalX(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateLocalY(double ang, Matrix4d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm02 = -sin * m00 + cos * m02;
+ double nm12 = -sin * m10 + cos * m12;
+ double nm22 = -sin * m20 + cos * m22;
+ double nm32 = -sin * m30 + cos * m32;
+ dest
+ ._m00(cos * m00 + sin * m02)
+ ._m01(m01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(cos * m10 + sin * m12)
+ ._m11(m11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(cos * m20 + sin * m22)
+ ._m21(m21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(cos * m30 + sin * m32)
+ ._m31(m31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @return this
+ */
+ public Matrix4d rotateLocalY(double ang) {
+ return rotateLocalY(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(double) rotationZ()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationZ(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateLocalZ(double ang, Matrix4d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm01 = sin * m00 + cos * m01;
+ double nm11 = sin * m10 + cos * m11;
+ double nm21 = sin * m20 + cos * m21;
+ double nm31 = sin * m30 + cos * m31;
+ dest
+ ._m00(cos * m00 - sin * m01)
+ ._m01(nm01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(cos * m10 - sin * m11)
+ ._m11(nm11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(cos * m20 - sin * m21)
+ ._m21(nm21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(cos * m30 - sin * m31)
+ ._m31(nm31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @return this
+ */
+ public Matrix4d rotateLocalZ(double ang) {
+ return rotateLocalZ(ang, this);
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(m00);
+ out.writeDouble(m01);
+ out.writeDouble(m02);
+ out.writeDouble(m03);
+ out.writeDouble(m10);
+ out.writeDouble(m11);
+ out.writeDouble(m12);
+ out.writeDouble(m13);
+ out.writeDouble(m20);
+ out.writeDouble(m21);
+ out.writeDouble(m22);
+ out.writeDouble(m23);
+ out.writeDouble(m30);
+ out.writeDouble(m31);
+ out.writeDouble(m32);
+ out.writeDouble(m33);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ _m00(in.readDouble()).
+ _m01(in.readDouble()).
+ _m02(in.readDouble()).
+ _m03(in.readDouble()).
+ _m10(in.readDouble()).
+ _m11(in.readDouble()).
+ _m12(in.readDouble()).
+ _m13(in.readDouble()).
+ _m20(in.readDouble()).
+ _m21(in.readDouble()).
+ _m22(in.readDouble()).
+ _m23(in.readDouble()).
+ _m30(in.readDouble()).
+ _m31(in.readDouble()).
+ _m32(in.readDouble()).
+ _m33(in.readDouble()).
+ determineProperties();
+ }
+
+ public Matrix4d rotateX(double ang, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationX(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double x = m30, y = m31, z = m32;
+ return dest.rotationX(ang).setTranslation(x, y, z);
+ }
+ return rotateXInternal(ang, dest);
+ }
+ private Matrix4d rotateXInternal(double ang, Matrix4d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm11 = cos;
+ double rm12 = sin;
+ double rm21 = -sin;
+ double rm22 = cos;
+
+ // add temporaries for dependent values
+ double nm10 = m10 * rm11 + m20 * rm12;
+ double nm11 = m11 * rm11 + m21 * rm12;
+ double nm12 = m12 * rm11 + m22 * rm12;
+ double nm13 = m13 * rm11 + m23 * rm12;
+ // set non-dependent values directly
+ dest._m20(m10 * rm21 + m20 * rm22)
+ ._m21(m11 * rm21 + m21 * rm22)
+ ._m22(m12 * rm21 + m22 * rm22)
+ ._m23(m13 * rm21 + m23 * rm22)
+ // set other values
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m00(m00)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4d rotateX(double ang) {
+ return rotateX(ang, this);
+ }
+
+ public Matrix4d rotateY(double ang, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationY(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double x = m30, y = m31, z = m32;
+ return dest.rotationY(ang).setTranslation(x, y, z);
+ }
+ return rotateYInternal(ang, dest);
+ }
+ private Matrix4d rotateYInternal(double ang, Matrix4d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm00 = cos;
+ double rm02 = -sin;
+ double rm20 = sin;
+ double rm22 = cos;
+
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m20 * rm02;
+ double nm01 = m01 * rm00 + m21 * rm02;
+ double nm02 = m02 * rm00 + m22 * rm02;
+ double nm03 = m03 * rm00 + m23 * rm02;
+ // set non-dependent values directly
+ dest._m20(m00 * rm20 + m20 * rm22)
+ ._m21(m01 * rm20 + m21 * rm22)
+ ._m22(m02 * rm20 + m22 * rm22)
+ ._m23(m03 * rm20 + m23 * rm22)
+ // set other values
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(m10)
+ ._m11(m11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4d rotateY(double ang) {
+ return rotateY(ang, this);
+ }
+
+ public Matrix4d rotateZ(double ang, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZ(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double x = m30, y = m31, z = m32;
+ return dest.rotationZ(ang).setTranslation(x, y, z);
+ }
+ return rotateZInternal(ang, dest);
+ }
+ private Matrix4d rotateZInternal(double ang, Matrix4d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ return rotateTowardsXY(sin, cos, dest);
+ }
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4d rotateZ(double ang) {
+ return rotateZ(ang, this);
+ }
+
+ /**
+ * Apply rotation about the Z axis to align the local +X
towards (dirX, dirY)
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * The vector (dirX, dirY)
must be a unit vector.
+ *
+ * @param dirX
+ * the x component of the normalized direction
+ * @param dirY
+ * the y component of the normalized direction
+ * @return this
+ */
+ public Matrix4d rotateTowardsXY(double dirX, double dirY) {
+ return rotateTowardsXY(dirX, dirY, this);
+ }
+
+ public Matrix4d rotateTowardsXY(double dirX, double dirY, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationTowardsXY(dirX, dirY);
+ double rm00 = dirY;
+ double rm01 = dirX;
+ double rm10 = -dirX;
+ double rm11 = dirY;
+ double nm00 = m00 * rm00 + m10 * rm01;
+ double nm01 = m01 * rm00 + m11 * rm01;
+ double nm02 = m02 * rm00 + m12 * rm01;
+ double nm03 = m03 * rm00 + m13 * rm01;
+ dest._m10(m00 * rm10 + m10 * rm11)
+ ._m11(m01 * rm10 + m11 * rm11)
+ ._m12(m02 * rm10 + m12 * rm11)
+ ._m13(m03 * rm10 + m13 * rm11)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.x
radians about the X axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4d rotateXYZ(Vector3d angles) {
+ return rotateXYZ(angles.x, angles.y, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix4d rotateXYZ(double angleX, double angleY, double angleZ, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationXYZ(angleX, angleY, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
+ } else if ((properties & PROPERTY_AFFINE) != 0)
+ return dest.rotateAffineXYZ(angleX, angleY, angleZ);
+ return rotateXYZInternal(angleX, angleY, angleZ, dest);
+ }
+ private Matrix4d rotateXYZInternal(double angleX, double angleY, double angleZ, Matrix4d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm10 = m10 * cosX + m20 * sinX;
+ double nm11 = m11 * cosX + m21 * sinX;
+ double nm12 = m12 * cosX + m22 * sinX;
+ double nm13 = m13 * cosX + m23 * sinX;
+ double nm20 = m10 * m_sinX + m20 * cosX;
+ double nm21 = m11 * m_sinX + m21 * cosX;
+ double nm22 = m12 * m_sinX + m22 * cosX;
+ double nm23 = m13 * m_sinX + m23 * cosX;
+ // rotateY
+ double nm00 = m00 * cosY + nm20 * m_sinY;
+ double nm01 = m01 * cosY + nm21 * m_sinY;
+ double nm02 = m02 * cosY + nm22 * m_sinY;
+ double nm03 = m03 * cosY + nm23 * m_sinY;
+ dest._m20(m00 * sinY + nm20 * cosY)
+ ._m21(m01 * sinY + nm21 * cosY)
+ ._m22(m02 * sinY + nm22 * cosY)
+ ._m23(m03 * sinY + nm23 * cosY)
+ // rotateZ
+ ._m00(nm00 * cosZ + nm10 * sinZ)
+ ._m01(nm01 * cosZ + nm11 * sinZ)
+ ._m02(nm02 * cosZ + nm12 * sinZ)
+ ._m03(nm03 * cosZ + nm13 * sinZ)
+ ._m10(nm00 * m_sinZ + nm10 * cosZ)
+ ._m11(nm01 * m_sinZ + nm11 * cosZ)
+ ._m12(nm02 * m_sinZ + nm12 * cosZ)
+ ._m13(nm03 * m_sinZ + nm13 * cosZ)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ) {
+ return rotateAffineXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationXYZ(angleX, angleY, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
+ }
+ return rotateAffineXYZInternal(angleX, angleY, angleZ, dest);
+ }
+ private Matrix4d rotateAffineXYZInternal(double angleX, double angleY, double angleZ, Matrix4d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm10 = m10 * cosX + m20 * sinX;
+ double nm11 = m11 * cosX + m21 * sinX;
+ double nm12 = m12 * cosX + m22 * sinX;
+ double nm20 = m10 * m_sinX + m20 * cosX;
+ double nm21 = m11 * m_sinX + m21 * cosX;
+ double nm22 = m12 * m_sinX + m22 * cosX;
+ // rotateY
+ double nm00 = m00 * cosY + nm20 * m_sinY;
+ double nm01 = m01 * cosY + nm21 * m_sinY;
+ double nm02 = m02 * cosY + nm22 * m_sinY;
+ dest._m20(m00 * sinY + nm20 * cosY)
+ ._m21(m01 * sinY + nm21 * cosY)
+ ._m22(m02 * sinY + nm22 * cosY)
+ ._m23(0.0)
+ // rotateZ
+ ._m00(nm00 * cosZ + nm10 * sinZ)
+ ._m01(nm01 * cosZ + nm11 * sinZ)
+ ._m02(nm02 * cosZ + nm12 * sinZ)
+ ._m03(0.0)
+ ._m10(nm00 * m_sinZ + nm10 * cosZ)
+ ._m11(nm01 * m_sinZ + nm11 * cosZ)
+ ._m12(nm02 * m_sinZ + nm12 * cosZ)
+ ._m13(0.0)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.z
radians about the Z axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.x
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4d rotateZYX(Vector3d angles) {
+ return rotateZYX(angles.z, angles.y, angles.x);
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4d rotateZYX(double angleZ, double angleY, double angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix4d rotateZYX(double angleZ, double angleY, double angleX, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZYX(angleZ, angleY, angleX);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz);
+ } else if ((properties & PROPERTY_AFFINE) != 0)
+ return dest.rotateAffineZYX(angleZ, angleY, angleX);
+ return rotateZYXInternal(angleZ, angleY, angleX, dest);
+ }
+ private Matrix4d rotateZYXInternal(double angleZ, double angleY, double angleX, Matrix4d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = m00 * cosZ + m10 * sinZ;
+ double nm01 = m01 * cosZ + m11 * sinZ;
+ double nm02 = m02 * cosZ + m12 * sinZ;
+ double nm03 = m03 * cosZ + m13 * sinZ;
+ double nm10 = m00 * m_sinZ + m10 * cosZ;
+ double nm11 = m01 * m_sinZ + m11 * cosZ;
+ double nm12 = m02 * m_sinZ + m12 * cosZ;
+ double nm13 = m03 * m_sinZ + m13 * cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY + m20 * cosY;
+ double nm21 = nm01 * sinY + m21 * cosY;
+ double nm22 = nm02 * sinY + m22 * cosY;
+ double nm23 = nm03 * sinY + m23 * cosY;
+ dest._m00(nm00 * cosY + m20 * m_sinY)
+ ._m01(nm01 * cosY + m21 * m_sinY)
+ ._m02(nm02 * cosY + m22 * m_sinY)
+ ._m03(nm03 * cosY + m23 * m_sinY)
+ // rotateX
+ ._m10(nm10 * cosX + nm20 * sinX)
+ ._m11(nm11 * cosX + nm21 * sinX)
+ ._m12(nm12 * cosX + nm22 * sinX)
+ ._m13(nm13 * cosX + nm23 * sinX)
+ ._m20(nm10 * m_sinX + nm20 * cosX)
+ ._m21(nm11 * m_sinX + nm21 * cosX)
+ ._m22(nm12 * m_sinX + nm22 * cosX)
+ ._m23(nm13 * m_sinX + nm23 * cosX)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX) {
+ return rotateAffineZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX, Matrix4d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = m00 * cosZ + m10 * sinZ;
+ double nm01 = m01 * cosZ + m11 * sinZ;
+ double nm02 = m02 * cosZ + m12 * sinZ;
+ double nm10 = m00 * m_sinZ + m10 * cosZ;
+ double nm11 = m01 * m_sinZ + m11 * cosZ;
+ double nm12 = m02 * m_sinZ + m12 * cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY + m20 * cosY;
+ double nm21 = nm01 * sinY + m21 * cosY;
+ double nm22 = nm02 * sinY + m22 * cosY;
+ dest._m00(nm00 * cosY + m20 * m_sinY)
+ ._m01(nm01 * cosY + m21 * m_sinY)
+ ._m02(nm02 * cosY + m22 * m_sinY)
+ ._m03(0.0)
+ // rotateX
+ ._m10(nm10 * cosX + nm20 * sinX)
+ ._m11(nm11 * cosX + nm21 * sinX)
+ ._m12(nm12 * cosX + nm22 * sinX)
+ ._m13(0.0)
+ ._m20(nm10 * m_sinX + nm20 * cosX)
+ ._m21(nm11 * m_sinX + nm21 * cosX)
+ ._m22(nm12 * m_sinX + nm22 * cosX)
+ ._m23(0.0)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.y
radians about the Y axis, followed by a rotation of angles.x
radians about the X axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4d rotateYXZ(Vector3d angles) {
+ return rotateYXZ(angles.y, angles.x, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix4d rotateYXZ(double angleY, double angleX, double angleZ, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationYXZ(angleY, angleX, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz);
+ } else if ((properties & PROPERTY_AFFINE) != 0)
+ return dest.rotateAffineYXZ(angleY, angleX, angleZ);
+ return rotateYXZInternal(angleY, angleX, angleZ, dest);
+ }
+ private Matrix4d rotateYXZInternal(double angleY, double angleX, double angleZ, Matrix4d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm20 = m00 * sinY + m20 * cosY;
+ double nm21 = m01 * sinY + m21 * cosY;
+ double nm22 = m02 * sinY + m22 * cosY;
+ double nm23 = m03 * sinY + m23 * cosY;
+ double nm00 = m00 * cosY + m20 * m_sinY;
+ double nm01 = m01 * cosY + m21 * m_sinY;
+ double nm02 = m02 * cosY + m22 * m_sinY;
+ double nm03 = m03 * cosY + m23 * m_sinY;
+ // rotateX
+ double nm10 = m10 * cosX + nm20 * sinX;
+ double nm11 = m11 * cosX + nm21 * sinX;
+ double nm12 = m12 * cosX + nm22 * sinX;
+ double nm13 = m13 * cosX + nm23 * sinX;
+ dest._m20(m10 * m_sinX + nm20 * cosX)
+ ._m21(m11 * m_sinX + nm21 * cosX)
+ ._m22(m12 * m_sinX + nm22 * cosX)
+ ._m23(m13 * m_sinX + nm23 * cosX)
+ // rotateZ
+ ._m00(nm00 * cosZ + nm10 * sinZ)
+ ._m01(nm01 * cosZ + nm11 * sinZ)
+ ._m02(nm02 * cosZ + nm12 * sinZ)
+ ._m03(nm03 * cosZ + nm13 * sinZ)
+ ._m10(nm00 * m_sinZ + nm10 * cosZ)
+ ._m11(nm01 * m_sinZ + nm11 * cosZ)
+ ._m12(nm02 * m_sinZ + nm12 * cosZ)
+ ._m13(nm03 * m_sinZ + nm13 * cosZ)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ) {
+ return rotateAffineYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ, Matrix4d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm20 = m00 * sinY + m20 * cosY;
+ double nm21 = m01 * sinY + m21 * cosY;
+ double nm22 = m02 * sinY + m22 * cosY;
+ double nm00 = m00 * cosY + m20 * m_sinY;
+ double nm01 = m01 * cosY + m21 * m_sinY;
+ double nm02 = m02 * cosY + m22 * m_sinY;
+ // rotateX
+ double nm10 = m10 * cosX + nm20 * sinX;
+ double nm11 = m11 * cosX + nm21 * sinX;
+ double nm12 = m12 * cosX + nm22 * sinX;
+ dest._m20(m10 * m_sinX + nm20 * cosX)
+ ._m21(m11 * m_sinX + nm21 * cosX)
+ ._m22(m12 * m_sinX + nm22 * cosX)
+ ._m23(0.0)
+ // rotateZ
+ ._m00(nm00 * cosZ + nm10 * sinZ)
+ ._m01(nm01 * cosZ + nm11 * sinZ)
+ ._m02(nm02 * cosZ + nm12 * sinZ)
+ ._m03(0.0)
+ ._m10(nm00 * m_sinZ + nm10 * cosZ)
+ ._m11(nm01 * m_sinZ + nm11 * cosZ)
+ ._m12(nm02 * m_sinZ + nm12 * cosZ)
+ ._m13(0.0)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4f) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4f)
+ *
+ * @param angleAxis
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d rotation(AxisAngle4f angleAxis) {
+ return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4d) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4d)
+ *
+ * @param angleAxis
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d rotation(AxisAngle4d angleAxis) {
+ return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z);
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniondc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaterniondc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4d rotation(Quaterniondc quat) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw;
+ double xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz;
+ double yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz;
+ double xw = quat.x() * quat.w(), dxw = xw + xw;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ _m00(w2 + x2 - z2 - y2).
+ _m01(dxy + dzw).
+ _m02(dxz - dyw).
+ _m10(-dzw + dxy).
+ _m11(y2 - z2 + w2 - x2).
+ _m12(dyz + dxw).
+ _m20(dyw + dxz).
+ _m21(dyz - dxw).
+ _m22(z2 - y2 - x2 + w2).
+ _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaternionfc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaternionfc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4d rotation(Quaternionfc quat) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw;
+ double xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz;
+ double yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz;
+ double xw = quat.x() * quat.w(), dxw = xw + xw;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ _m00(w2 + x2 - z2 - y2).
+ _m01(dxy + dzw).
+ _m02(dxz - dyw).
+ _m10(-dzw + dxy).
+ _m11(y2 - z2 + w2 - x2).
+ _m12(dyz + dxw).
+ _m20(dyw + dxz).
+ _m21(dyz - dxw).
+ _m22(z2 - y2 - x2 + w2).
+ _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(double, double, double)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @return this
+ */
+ public Matrix4d translationRotateScale(double tx, double ty, double tz,
+ double qx, double qy, double qz, double qw,
+ double sx, double sy, double sz) {
+ double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz;
+ double q00 = dqx * qx;
+ double q11 = dqy * qy;
+ double q22 = dqz * qz;
+ double q01 = dqx * qy;
+ double q02 = dqx * qz;
+ double q03 = dqx * qw;
+ double q12 = dqy * qz;
+ double q13 = dqy * qw;
+ double q23 = dqz * qw;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ _m00(sx - (q11 + q22) * sx).
+ _m01((q01 + q23) * sx).
+ _m02((q02 - q13) * sx).
+ _m03(0.0).
+ _m10((q01 - q23) * sy).
+ _m11(sy - (q22 + q00) * sy).
+ _m12((q12 + q03) * sy).
+ _m13(0.0).
+ _m20((q02 + q13) * sz).
+ _m21((q12 - q03) * sz).
+ _m22(sz - (q11 + q00) * sz).
+ _m23(0.0).
+ _m30(tx).
+ _m31(ty).
+ _m32(tz).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0);
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScale(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3dc)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(Vector3dc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScale(Vector3dc translation,
+ Quaterniondc quat,
+ Vector3dc scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(scale)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(double)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param scale
+ * the scaling factor for all three axes
+ * @return this
+ */
+ public Matrix4d translationRotateScale(double tx, double ty, double tz,
+ double qx, double qy, double qz, double qw,
+ double scale) {
+ return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3dc)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(double)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScale(Vector3dc translation,
+ Quaterniondc quat,
+ double scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(double)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScale(Vector3fc translation,
+ Quaternionfc quat,
+ double scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(double, double, double, double, double, double, double, double, double, double)
+ * @see #invert()
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @return this
+ */
+ public Matrix4d translationRotateScaleInvert(double tx, double ty, double tz,
+ double qx, double qy, double qz, double qw,
+ double sx, double sy, double sz) {
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ if (one)
+ return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, sx, sy, sz).invertOrthonormal(this);
+ double nqx = -qx, nqy = -qy, nqz = -qz;
+ double dqx = nqx + nqx;
+ double dqy = nqy + nqy;
+ double dqz = nqz + nqz;
+ double q00 = dqx * nqx;
+ double q11 = dqy * nqy;
+ double q22 = dqz * nqz;
+ double q01 = dqx * nqy;
+ double q02 = dqx * nqz;
+ double q03 = dqx * qw;
+ double q12 = dqy * nqz;
+ double q13 = dqy * qw;
+ double q23 = dqz * qw;
+ double isx = 1/sx, isy = 1/sy, isz = 1/sz;
+ _m00(isx * (1.0 - q11 - q22)).
+ _m01(isy * (q01 + q23)).
+ _m02(isz * (q02 - q13)).
+ _m03(0.0).
+ _m10(isx * (q01 - q23)).
+ _m11(isy * (1.0 - q22 - q00)).
+ _m12(isz * (q12 + q03)).
+ _m13(0.0).
+ _m20(isx * (q02 + q13)).
+ _m21(isy * (q12 - q03)).
+ _m22(isz * (1.0 - q11 - q00)).
+ _m23(0.0).
+ _m30(-m00 * tx - m10 * ty - m20 * tz).
+ _m31(-m01 * tx - m11 * ty - m21 * tz).
+ _m32(-m02 * tx - m12 * ty - m22 * tz).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(Vector3dc, Quaterniondc, Vector3dc)
+ * @see #invert()
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScaleInvert(Vector3dc translation,
+ Quaterniondc quat,
+ Vector3dc scale) {
+ return translationRotateScaleInvert(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(Vector3fc, Quaternionfc, Vector3fc)
+ * @see #invert()
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScaleInvert(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale) {
+ return translationRotateScaleInvert(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(Vector3dc, Quaterniondc, double)
+ * @see #invert()
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScaleInvert(Vector3dc translation,
+ Quaterniondc quat,
+ double scale) {
+ return translationRotateScaleInvert(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(Vector3fc, Quaternionfc, double)
+ * @see #invert()
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4d translationRotateScaleInvert(Vector3fc translation,
+ Quaternionfc quat,
+ double scale) {
+ return translationRotateScaleInvert(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation - and possibly scaling - transformation specified by the quaternion (qx, qy, qz, qw)
, S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
and M
is an {@link #isAffine() affine} matrix.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mulAffine(m)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(double, double, double)
+ * @see #mulAffine(Matrix4dc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @param m
+ * the {@link #isAffine() affine} matrix to multiply by
+ * @return this
+ */
+ public Matrix4d translationRotateScaleMulAffine(double tx, double ty, double tz,
+ double qx, double qy, double qz, double qw,
+ double sx, double sy, double sz,
+ Matrix4d m) {
+ double w2 = qw * qw;
+ double x2 = qx * qx;
+ double y2 = qy * qy;
+ double z2 = qz * qz;
+ double zw = qz * qw;
+ double xy = qx * qy;
+ double xz = qx * qz;
+ double yw = qy * qw;
+ double yz = qy * qz;
+ double xw = qx * qw;
+ double nm00 = w2 + x2 - z2 - y2;
+ double nm01 = xy + zw + zw + xy;
+ double nm02 = xz - yw + xz - yw;
+ double nm10 = -zw + xy - zw + xy;
+ double nm11 = y2 - z2 + w2 - x2;
+ double nm12 = yz + yz + xw + xw;
+ double nm20 = yw + xz + xz + yw;
+ double nm21 = yz + yz - xw - xw;
+ double nm22 = z2 - y2 - x2 + w2;
+ double m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02;
+ double m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02;
+ this.m02 = nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02;
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m03 = 0.0;
+ double m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12;
+ double m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12;
+ this.m12 = nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m13 = 0.0;
+ double m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22;
+ double m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22;
+ this.m22 = nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m23 = 0.0;
+ double m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx;
+ double m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty;
+ this.m32 = nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz;
+ this.m30 = m30;
+ this.m31 = m31;
+ this.m33 = 1.0;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ properties = PROPERTY_AFFINE | (one && (m.properties & PROPERTY_ORTHONORMAL) != 0 ? PROPERTY_ORTHONORMAL : 0);
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is the given translation
,
+ * R
is a rotation - and possibly scaling - transformation specified by the given quaternion, S
is a scaling transformation
+ * which scales the axes by scale
and M
is an {@link #isAffine() affine} matrix.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale).mulAffine(m)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaterniondc)
+ * @see #mulAffine(Matrix4dc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @param m
+ * the {@link #isAffine() affine} matrix to multiply by
+ * @return this
+ */
+ public Matrix4d translationRotateScaleMulAffine(Vector3fc translation,
+ Quaterniondc quat,
+ Vector3fc scale,
+ Matrix4d m) {
+ return translationRotateScaleMulAffine(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z(), m);
+ }
+
+ /**
+ * Set this
matrix to T * R
, where T
is a translation by the given (tx, ty, tz)
and
+ * R
is a rotation - and possibly scaling - transformation specified by the quaternion (qx, qy, qz, qw)
.
+ *
+ * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @return this
+ */
+ public Matrix4d translationRotate(double tx, double ty, double tz, double qx, double qy, double qz, double qw) {
+ double w2 = qw * qw;
+ double x2 = qx * qx;
+ double y2 = qy * qy;
+ double z2 = qz * qz;
+ double zw = qz * qw;
+ double xy = qx * qy;
+ double xz = qx * qz;
+ double yw = qy * qw;
+ double yz = qy * qz;
+ double xw = qx * qw;
+ this.m00 = w2 + x2 - z2 - y2;
+ this.m01 = xy + zw + zw + xy;
+ this.m02 = xz - yw + xz - yw;
+ this.m10 = -zw + xy - zw + xy;
+ this.m11 = y2 - z2 + w2 - x2;
+ this.m12 = yz + yz + xw + xw;
+ this.m20 = yw + xz + xz + yw;
+ this.m21 = yz + yz - xw - xw;
+ this.m22 = z2 - y2 - x2 + w2;
+ this.m30 = tx;
+ this.m31 = ty;
+ this.m32 = tz;
+ this.m33 = 1.0;
+ this.properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R
, where T
is a translation by the given (tx, ty, tz)
and
+ * R
is a rotation - and possibly scaling - transformation specified by the given quaternion.
+ *
+ * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param quat
+ * the quaternion representing a rotation
+ * @return this
+ */
+ public Matrix4d translationRotate(double tx, double ty, double tz, Quaterniondc quat) {
+ return translationRotate(tx, ty, tz, quat.x(), quat.y(), quat.z(), quat.w());
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotate(Quaterniondc quat, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(quat);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(quat, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAffine(quat, dest);
+ return rotateGeneric(quat, dest);
+ }
+ private Matrix4d rotateGeneric(Quaterniondc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = -dzw + dxy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotate(Quaternionfc quat, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(quat);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(quat, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAffine(quat, dest);
+ return rotateGeneric(quat, dest);
+ }
+ private Matrix4d rotateGeneric(Quaternionfc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = xy + zw + zw + xy;
+ double rm02 = xz - yw + xz - yw;
+ double rm10 = -zw + xy - zw + xy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = yz + yz + xw + xw;
+ double rm20 = yw + xz + xz + yw;
+ double rm21 = yz + yz - xw - xw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4d rotate(Quaterniondc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4d rotate(Quaternionfc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this {@link #isAffine() affine} matrix and store
+ * the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateAffine(Quaterniondc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = -dzw + dxy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4d rotateAffine(Quaterniondc quat) {
+ return rotateAffine(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateTranslation(Quaterniondc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = -dzw + dxy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ dest._m20(rm20)
+ ._m21(rm21)
+ ._m22(rm22)
+ ._m23(0.0)
+ ._m00(rm00)
+ ._m01(rm01)
+ ._m02(rm02)
+ ._m03(0.0)
+ ._m10(rm10)
+ ._m11(rm11)
+ ._m12(rm12)
+ ._m13(0.0)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(1.0)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateTranslation(Quaternionfc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = xy + zw + zw + xy;
+ double rm02 = xz - yw + xz - yw;
+ double rm10 = -zw + xy - zw + xy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = yz + yz + xw + xw;
+ double rm20 = yw + xz + xz + yw;
+ double rm21 = yz + yz - xw - xw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = rm00;
+ double nm01 = rm01;
+ double nm02 = rm02;
+ double nm10 = rm10;
+ double nm11 = rm11;
+ double nm12 = rm12;
+ dest._m20(rm20)
+ ._m21(rm21)
+ ._m22(rm22)
+ ._m23(0.0)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(1.0)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateLocal(Quaterniondc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = dxy + dzw;
+ double lm02 = dxz - dyw;
+ double lm10 = -dzw + dxy;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = dyz + dxw;
+ double lm20 = dyw + dxz;
+ double lm21 = dyz - dxw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm03 = m03;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm13 = m13;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ double nm23 = m23;
+ double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4d rotateLocal(Quaterniondc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this {@link #isAffine() affine} matrix and store
+ * the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateAffine(Quaternionfc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = xy + zw + zw + xy;
+ double rm02 = xz - yw + xz - yw;
+ double rm10 = -zw + xy - zw + xy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = yz + yz + xw + xw;
+ double rm20 = yw + xz + xz + yw;
+ double rm21 = yz + yz - xw - xw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4d rotateAffine(Quaternionfc quat) {
+ return rotateAffine(quat, this);
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateLocal(Quaternionfc quat, Matrix4d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = xy + zw + zw + xy;
+ double lm02 = xz - yw + xz - yw;
+ double lm10 = -zw + xy - zw + xy;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = yz + yz + xw + xw;
+ double lm20 = yw + xz + xz + yw;
+ double lm21 = yz + yz - xw - xw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm03 = m03;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm13 = m13;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ double nm23 = m23;
+ double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4d rotateLocal(Quaternionfc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d rotate(AxisAngle4f axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotate(AxisAngle4f axisAngle, Matrix4d dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4d)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d rotate(AxisAngle4d axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4d)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotate(AxisAngle4d axisAngle, Matrix4d dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3dc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d rotate(double angle, Vector3dc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3dc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotate(double angle, Vector3dc axis, Matrix4d dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d rotate(double angle, Vector3fc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotate(double angle, Vector3fc axis, Matrix4d dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ public Vector4d getRow(int row, Vector4d dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ dest.x = m00;
+ dest.y = m10;
+ dest.z = m20;
+ dest.w = m30;
+ break;
+ case 1:
+ dest.x = m01;
+ dest.y = m11;
+ dest.z = m21;
+ dest.w = m31;
+ break;
+ case 2:
+ dest.x = m02;
+ dest.y = m12;
+ dest.z = m22;
+ dest.w = m32;
+ break;
+ case 3:
+ dest.x = m03;
+ dest.y = m13;
+ dest.z = m23;
+ dest.w = m33;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ public Vector3d getRow(int row, Vector3d dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ dest.x = m00;
+ dest.y = m10;
+ dest.z = m20;
+ break;
+ case 1:
+ dest.x = m01;
+ dest.y = m11;
+ dest.z = m21;
+ break;
+ case 2:
+ dest.x = m02;
+ dest.y = m12;
+ dest.z = m22;
+ break;
+ case 3:
+ dest.x = m03;
+ dest.y = m13;
+ dest.z = m23;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..3]
+ */
+ public Matrix4d setRow(int row, Vector4dc src) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ return _m00(src.x())._m10(src.y())._m20(src.z())._m30(src.w())._properties(0);
+ case 1:
+ return _m01(src.x())._m11(src.y())._m21(src.z())._m31(src.w())._properties(0);
+ case 2:
+ return _m02(src.x())._m12(src.y())._m22(src.z())._m32(src.w())._properties(0);
+ case 3:
+ return _m03(src.x())._m13(src.y())._m23(src.z())._m33(src.w())._properties(0);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public Vector4d getColumn(int column, Vector4d dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ dest.x = m00;
+ dest.y = m01;
+ dest.z = m02;
+ dest.w = m03;
+ break;
+ case 1:
+ dest.x = m10;
+ dest.y = m11;
+ dest.z = m12;
+ dest.w = m13;
+ break;
+ case 2:
+ dest.x = m20;
+ dest.y = m21;
+ dest.z = m22;
+ dest.w = m23;
+ break;
+ case 3:
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ dest.w = m33;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ public Vector3d getColumn(int column, Vector3d dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ dest.x = m00;
+ dest.y = m01;
+ dest.z = m02;
+ break;
+ case 1:
+ dest.x = m10;
+ dest.y = m11;
+ dest.z = m12;
+ break;
+ case 2:
+ dest.x = m20;
+ dest.y = m21;
+ dest.z = m22;
+ break;
+ case 3:
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ public Matrix4d setColumn(int column, Vector4dc src) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ return _m00(src.x())._m01(src.y())._m02(src.z())._m03(src.w())._properties(0);
+ case 1:
+ return _m10(src.x())._m11(src.y())._m12(src.z())._m13(src.w())._properties(0);
+ case 2:
+ return _m20(src.x())._m21(src.y())._m22(src.z())._m23(src.w())._properties(0);
+ case 3:
+ return _m30(src.x())._m31(src.y())._m32(src.z())._m33(src.w())._properties(0);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public double get(int column, int row) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given column and row to the specified value.
+ *
+ * @param column
+ * the colum index in [0..3]
+ * @param row
+ * the row index in [0..3]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix4d set(int column, int row, double value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ public double getRowColumn(int row, int column) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given row and column to the specified value.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param column
+ * the colum index in [0..3]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix4d setRowColumn(int row, int column, double value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into the upper left 3x3 submatrix of this
.
+ * All other values of this
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4dc)} to set a given Matrix4f to only the upper left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see #set3x3(Matrix4dc)
+ *
+ * @return this
+ */
+ public Matrix4d normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into the upper left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4dc)} to set a given Matrix4d to only the upper left 3x3 submatrix
+ * of a given matrix.
+ *
+ * @see #set3x3(Matrix4dc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d normal(Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix4d normalOrthonormal(Matrix4d dest) {
+ if (dest != this)
+ dest.set(this);
+ return dest._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+ private Matrix4d normalGeneric(Matrix4d dest) {
+ double m00m11 = m00 * m11;
+ double m01m10 = m01 * m10;
+ double m02m10 = m02 * m10;
+ double m00m12 = m00 * m12;
+ double m01m12 = m01 * m12;
+ double m02m11 = m02 * m11;
+ double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ double s = 1.0 / det;
+ /* Invert and transpose in one go */
+ double nm00 = (m11 * m22 - m21 * m12) * s;
+ double nm01 = (m20 * m12 - m10 * m22) * s;
+ double nm02 = (m10 * m21 - m20 * m11) * s;
+ double nm10 = (m21 * m02 - m01 * m22) * s;
+ double nm11 = (m00 * m22 - m20 * m02) * s;
+ double nm12 = (m20 * m01 - m00 * m21) * s;
+ double nm20 = (m01m12 - m02m11) * s;
+ double nm21 = (m02m10 - m00m12) * s;
+ double nm22 = (m00m11 - m01m10) * s;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(0.0)
+ ._m30(0.0)
+ ._m31(0.0)
+ ._m32(0.0)
+ ._m33(1.0)
+ ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link Matrix3d#set(Matrix4dc)} to set a given Matrix3d to only the upper left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see Matrix3d#set(Matrix4dc)
+ * @see #get3x3(Matrix3d)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d normal(Matrix3d dest) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix3d normalOrthonormal(Matrix3d dest) {
+ dest.set(this);
+ return dest;
+ }
+ private Matrix3d normalGeneric(Matrix3d dest) {
+ double m00m11 = m00 * m11;
+ double m01m10 = m01 * m10;
+ double m02m10 = m02 * m10;
+ double m00m12 = m00 * m12;
+ double m01m12 = m01 * m12;
+ double m02m11 = m02 * m11;
+ double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ double s = 1.0 / det;
+ /* Invert and transpose in one go */
+ return dest._m00((m11 * m22 - m21 * m12) * s)
+ ._m01((m20 * m12 - m10 * m22) * s)
+ ._m02((m10 * m21 - m20 * m11) * s)
+ ._m10((m21 * m02 - m01 * m22) * s)
+ ._m11((m00 * m22 - m20 * m02) * s)
+ ._m12((m20 * m01 - m00 * m21) * s)
+ ._m20((m01m12 - m02m11) * s)
+ ._m21((m02m10 - m00m12) * s)
+ ._m22((m00m11 - m01m10) * s);
+ }
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal()} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @return this
+ */
+ public Matrix4d cofactor3x3() {
+ return cofactor3x3(this);
+ }
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d cofactor3x3(Matrix3d dest) {
+ return dest._m00(m11 * m22 - m21 * m12)
+ ._m01(m20 * m12 - m10 * m22)
+ ._m02(m10 * m21 - m20 * m11)
+ ._m10(m21 * m02 - m01 * m22)
+ ._m11(m00 * m22 - m20 * m02)
+ ._m12(m20 * m01 - m00 * m21)
+ ._m20(m01 * m12 - m02 * m11)
+ ._m21(m02 * m10 - m00 * m12)
+ ._m22(m00 * m11 - m01 * m10);
+ }
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d cofactor3x3(Matrix4d dest) {
+ double nm10 = m21 * m02 - m01 * m22;
+ double nm11 = m00 * m22 - m20 * m02;
+ double nm12 = m20 * m01 - m00 * m21;
+ double nm20 = m01 * m12 - m11 * m02;
+ double nm21 = m02 * m10 - m12 * m00;
+ double nm22 = m00 * m11 - m10 * m01;
+ return dest
+ ._m00(m11 * m22 - m21 * m12)
+ ._m01(m20 * m12 - m10 * m22)
+ ._m02(m10 * m21 - m20 * m11)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(0.0)
+ ._m30(0.0)
+ ._m31(0.0)
+ ._m32(0.0)
+ ._m33(1.0)
+ ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Normalize the upper left 3x3 submatrix of this matrix.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @return this
+ */
+ public Matrix4d normalize3x3() {
+ return normalize3x3(this);
+ }
+
+ public Matrix4d normalize3x3(Matrix4d dest) {
+ double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ dest._m00(m00 * invXlen)._m01(m01 * invXlen)._m02(m02 * invXlen)
+ ._m10(m10 * invYlen)._m11(m11 * invYlen)._m12(m12 * invYlen)
+ ._m20(m20 * invZlen)._m21(m21 * invZlen)._m22(m22 * invZlen)
+ ._m30(m30)._m31(m31)._m32(m32)._m33(m33)
+ ._properties(properties);
+ return dest;
+ }
+
+ public Matrix3d normalize3x3(Matrix3d dest) {
+ double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ dest.m00(m00 * invXlen); dest.m01(m01 * invXlen); dest.m02(m02 * invXlen);
+ dest.m10(m10 * invYlen); dest.m11(m11 * invYlen); dest.m12(m12 * invYlen);
+ dest.m20(m20 * invZlen); dest.m21(m21 * invZlen); dest.m22(m22 * invZlen);
+ return dest;
+ }
+
+ public Vector4d unproject(double winX, double winY, double winZ, int[] viewport, Vector4d dest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double c = m00 * m13 - m03 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double e = m01 * m13 - m03 * m11;
+ double f = m02 * m13 - m03 * m12;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double i = m20 * m33 - m23 * m30;
+ double j = m21 * m32 - m22 * m31;
+ double k = m21 * m33 - m23 * m31;
+ double l = m22 * m33 - m23 * m32;
+ double det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0 / det;
+ double im00 = ( m11 * l - m12 * k + m13 * j) * det;
+ double im01 = (-m01 * l + m02 * k - m03 * j) * det;
+ double im02 = ( m31 * f - m32 * e + m33 * d) * det;
+ double im03 = (-m21 * f + m22 * e - m23 * d) * det;
+ double im10 = (-m10 * l + m12 * i - m13 * h) * det;
+ double im11 = ( m00 * l - m02 * i + m03 * h) * det;
+ double im12 = (-m30 * f + m32 * c - m33 * b) * det;
+ double im13 = ( m20 * f - m22 * c + m23 * b) * det;
+ double im20 = ( m10 * k - m11 * i + m13 * g) * det;
+ double im21 = (-m00 * k + m01 * i - m03 * g) * det;
+ double im22 = ( m30 * e - m31 * c + m33 * a) * det;
+ double im23 = (-m20 * e + m21 * c - m23 * a) * det;
+ double im30 = (-m10 * j + m11 * h - m12 * g) * det;
+ double im31 = ( m00 * j - m01 * h + m02 * g) * det;
+ double im32 = (-m30 * d + m31 * b - m32 * a) * det;
+ double im33 = ( m20 * d - m21 * b + m22 * a) * det;
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ double ndcZ = winZ+winZ-1.0;
+ double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33);
+ dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW;
+ dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW;
+ dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW;
+ dest.w = 1.0;
+ return dest;
+ }
+
+ public Vector3d unproject(double winX, double winY, double winZ, int[] viewport, Vector3d dest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double c = m00 * m13 - m03 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double e = m01 * m13 - m03 * m11;
+ double f = m02 * m13 - m03 * m12;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double i = m20 * m33 - m23 * m30;
+ double j = m21 * m32 - m22 * m31;
+ double k = m21 * m33 - m23 * m31;
+ double l = m22 * m33 - m23 * m32;
+ double det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0 / det;
+ double im00 = ( m11 * l - m12 * k + m13 * j) * det;
+ double im01 = (-m01 * l + m02 * k - m03 * j) * det;
+ double im02 = ( m31 * f - m32 * e + m33 * d) * det;
+ double im03 = (-m21 * f + m22 * e - m23 * d) * det;
+ double im10 = (-m10 * l + m12 * i - m13 * h) * det;
+ double im11 = ( m00 * l - m02 * i + m03 * h) * det;
+ double im12 = (-m30 * f + m32 * c - m33 * b) * det;
+ double im13 = ( m20 * f - m22 * c + m23 * b) * det;
+ double im20 = ( m10 * k - m11 * i + m13 * g) * det;
+ double im21 = (-m00 * k + m01 * i - m03 * g) * det;
+ double im22 = ( m30 * e - m31 * c + m33 * a) * det;
+ double im23 = (-m20 * e + m21 * c - m23 * a) * det;
+ double im30 = (-m10 * j + m11 * h - m12 * g) * det;
+ double im31 = ( m00 * j - m01 * h + m02 * g) * det;
+ double im32 = (-m30 * d + m31 * b - m32 * a) * det;
+ double im33 = ( m20 * d - m21 * b + m22 * a) * det;
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ double ndcZ = winZ+winZ-1.0;
+ double invW = 1.0 / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33);
+ dest.x = (im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW;
+ dest.y = (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW;
+ dest.z = (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW;
+ return dest;
+ }
+
+ public Vector4d unproject(Vector3dc winCoords, int[] viewport, Vector4d dest) {
+ return unproject(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Vector3d unproject(Vector3dc winCoords, int[] viewport, Vector3d dest) {
+ return unproject(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Matrix4d unprojectRay(double winX, double winY, int[] viewport, Vector3d originDest, Vector3d dirDest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double c = m00 * m13 - m03 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double e = m01 * m13 - m03 * m11;
+ double f = m02 * m13 - m03 * m12;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double i = m20 * m33 - m23 * m30;
+ double j = m21 * m32 - m22 * m31;
+ double k = m21 * m33 - m23 * m31;
+ double l = m22 * m33 - m23 * m32;
+ double det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0 / det;
+ double im00 = ( m11 * l - m12 * k + m13 * j) * det;
+ double im01 = (-m01 * l + m02 * k - m03 * j) * det;
+ double im02 = ( m31 * f - m32 * e + m33 * d) * det;
+ double im03 = (-m21 * f + m22 * e - m23 * d) * det;
+ double im10 = (-m10 * l + m12 * i - m13 * h) * det;
+ double im11 = ( m00 * l - m02 * i + m03 * h) * det;
+ double im12 = (-m30 * f + m32 * c - m33 * b) * det;
+ double im13 = ( m20 * f - m22 * c + m23 * b) * det;
+ double im20 = ( m10 * k - m11 * i + m13 * g) * det;
+ double im21 = (-m00 * k + m01 * i - m03 * g) * det;
+ double im22 = ( m30 * e - m31 * c + m33 * a) * det;
+ double im23 = (-m20 * e + m21 * c - m23 * a) * det;
+ double im30 = (-m10 * j + m11 * h - m12 * g) * det;
+ double im31 = ( m00 * j - m01 * h + m02 * g) * det;
+ double im32 = (-m30 * d + m31 * b - m32 * a) * det;
+ double im33 = ( m20 * d - m21 * b + m22 * a) * det;
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ double px = im00 * ndcX + im10 * ndcY + im30;
+ double py = im01 * ndcX + im11 * ndcY + im31;
+ double pz = im02 * ndcX + im12 * ndcY + im32;
+ double invNearW = 1.0 / (im03 * ndcX + im13 * ndcY - im23 + im33);
+ double nearX = (px - im20) * invNearW;
+ double nearY = (py - im21) * invNearW;
+ double nearZ = (pz - im22) * invNearW;
+ double invW0 = 1.0 / (im03 * ndcX + im13 * ndcY + im33);
+ double x0 = px * invW0;
+ double y0 = py * invW0;
+ double z0 = pz * invW0;
+ originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ;
+ dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ;
+ return this;
+ }
+
+ public Matrix4d unprojectRay(Vector2dc winCoords, int[] viewport, Vector3d originDest, Vector3d dirDest) {
+ return unprojectRay(winCoords.x(), winCoords.y(), viewport, originDest, dirDest);
+ }
+
+ public Vector4d unprojectInv(Vector3dc winCoords, int[] viewport, Vector4d dest) {
+ return unprojectInv(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Vector4d unprojectInv(double winX, double winY, double winZ, int[] viewport, Vector4d dest) {
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ double ndcZ = winZ+winZ-1.0;
+ double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33);
+ dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW;
+ dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW;
+ dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW;
+ dest.w = 1.0;
+ return dest;
+ }
+
+ public Vector3d unprojectInv(Vector3dc winCoords, int[] viewport, Vector3d dest) {
+ return unprojectInv(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Vector3d unprojectInv(double winX, double winY, double winZ, int[] viewport, Vector3d dest) {
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ double ndcZ = winZ+winZ-1.0;
+ double invW = 1.0 / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33);
+ dest.x = (m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW;
+ dest.y = (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW;
+ dest.z = (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW;
+ return dest;
+ }
+
+ public Matrix4d unprojectInvRay(Vector2dc winCoords, int[] viewport, Vector3d originDest, Vector3d dirDest) {
+ return unprojectInvRay(winCoords.x(), winCoords.y(), viewport, originDest, dirDest);
+ }
+
+ public Matrix4d unprojectInvRay(double winX, double winY, int[] viewport, Vector3d originDest, Vector3d dirDest) {
+ double ndcX = (winX-viewport[0])/viewport[2]*2.0-1.0;
+ double ndcY = (winY-viewport[1])/viewport[3]*2.0-1.0;
+ double px = m00 * ndcX + m10 * ndcY + m30;
+ double py = m01 * ndcX + m11 * ndcY + m31;
+ double pz = m02 * ndcX + m12 * ndcY + m32;
+ double invNearW = 1.0 / (m03 * ndcX + m13 * ndcY - m23 + m33);
+ double nearX = (px - m20) * invNearW;
+ double nearY = (py - m21) * invNearW;
+ double nearZ = (pz - m22) * invNearW;
+ double invW0 = 1.0 / (m03 * ndcX + m13 * ndcY + m33);
+ double x0 = px * invW0;
+ double y0 = py * invW0;
+ double z0 = pz * invW0;
+ originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ;
+ dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ;
+ return this;
+ }
+
+ public Vector4d project(double x, double y, double z, int[] viewport, Vector4d winCoordsDest) {
+ double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)));
+ double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW;
+ double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW;
+ double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW;
+ return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]),
+ Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]),
+ Math.fma(0.5, nz, 0.5),
+ 1.0);
+ }
+
+ public Vector3d project(double x, double y, double z, int[] viewport, Vector3d winCoordsDest) {
+ double invW = 1.0 / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)));
+ double nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW;
+ double ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW;
+ double nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW;
+ winCoordsDest.x = Math.fma(Math.fma(nx, 0.5, 0.5), viewport[2], viewport[0]);
+ winCoordsDest.y = Math.fma(Math.fma(ny, 0.5, 0.5), viewport[3], viewport[1]);
+ winCoordsDest.z = Math.fma(0.5, nz, 0.5);
+ return winCoordsDest;
+ }
+
+ public Vector4d project(Vector3dc position, int[] viewport, Vector4d dest) {
+ return project(position.x(), position.y(), position.z(), viewport, dest);
+ }
+
+ public Vector3d project(Vector3dc position, int[] viewport, Vector3d dest) {
+ return project(position.x(), position.y(), position.z(), viewport, dest);
+ }
+
+ public Matrix4d reflect(double a, double b, double c, double d, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.reflection(a, b, c, d);
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.reflection(a, b, c, d);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return reflectAffine(a, b, c, d, dest);
+ return reflectGeneric(a, b, c, d, dest);
+ }
+ private Matrix4d reflectAffine(double a, double b, double c, double d, Matrix4d dest) {
+ double da = a + a, db = b + b, dc = c + c, dd = d + d;
+ double rm00 = 1.0 - da * a;
+ double rm01 = -da * b;
+ double rm02 = -da * c;
+ double rm10 = -db * a;
+ double rm11 = 1.0 - db * b;
+ double rm12 = -db * c;
+ double rm20 = -dc * a;
+ double rm21 = -dc * b;
+ double rm22 = 1.0 - dc * c;
+ double rm30 = -dd * a;
+ double rm31 = -dd * b;
+ double rm32 = -dd * c;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ // matrix multiplication
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m33)
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+ private Matrix4d reflectGeneric(double a, double b, double c, double d, Matrix4d dest) {
+ double da = a + a, db = b + b, dc = c + c, dd = d + d;
+ double rm00 = 1.0 - da * a;
+ double rm01 = -da * b;
+ double rm02 = -da * c;
+ double rm10 = -db * a;
+ double rm11 = 1.0 - db * b;
+ double rm12 = -db * c;
+ double rm20 = -dc * a;
+ double rm21 = -dc * b;
+ double rm22 = 1.0 - dc * c;
+ double rm30 = -dd * a;
+ double rm31 = -dd * b;
+ double rm32 = -dd * c;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ // matrix multiplication
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4d reflect(double a, double b, double c, double d) {
+ return reflect(a, b, c, d, this);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz) {
+ return reflect(nx, ny, nz, px, py, pz, this);
+ }
+
+ public Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz, Matrix4d dest) {
+ double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ double nnx = nx * invLength;
+ double nny = ny * invLength;
+ double nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4d reflect(Vector3dc normal, Vector3dc point) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation relative to an implied normal vector of (0, 0, 1)
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4d reflect(Quaterniondc orientation, Vector3dc point) {
+ return reflect(orientation, point, this);
+ }
+
+ public Matrix4d reflect(Quaterniondc orientation, Vector3dc point, Matrix4d dest) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ double normalX = orientation.x() * num3 + orientation.w() * num2;
+ double normalY = orientation.y() * num3 - orientation.w() * num1;
+ double normalZ = 1.0 - (orientation.x() * num1 + orientation.y() * num2);
+ return reflect(normalX, normalY, normalZ, point.x(), point.y(), point.z(), dest);
+ }
+
+ public Matrix4d reflect(Vector3dc normal, Vector3dc point, Matrix4d dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z(), dest);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4d reflection(double a, double b, double c, double d) {
+ double da = a + a, db = b + b, dc = c + c, dd = d + d;
+ _m00(1.0 - da * a).
+ _m01(-da * b).
+ _m02(-da * c).
+ _m03(0.0).
+ _m10(-db * a).
+ _m11(1.0 - db * b).
+ _m12(-db * c).
+ _m13(0.0).
+ _m20(-dc * a).
+ _m21(-dc * b).
+ _m22(1.0 - dc * c).
+ _m23(0.0).
+ _m30(-dd * a).
+ _m31(-dd * b).
+ _m32(-dd * c).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4d reflection(double nx, double ny, double nz, double px, double py, double pz) {
+ double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ double nnx = nx * invLength;
+ double nny = ny * invLength;
+ double nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4d reflection(Vector3dc normal, Vector3dc point) {
+ return reflection(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4d reflection(Quaterniondc orientation, Vector3dc point) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ double normalX = orientation.x() * num3 + orientation.w() * num2;
+ double normalY = orientation.y() * num3 - orientation.w() * num1;
+ double normalZ = 1.0 - (orientation.x() * num1 + orientation.y() * num2);
+ return reflection(normalX, normalY, normalZ, point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrtho(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return orthoGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d orthoGeneric(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
+ double rm30 = (left + right) / (left - right);
+ double rm31 = (top + bottom) / (bottom - top);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest) {
+ return ortho(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ return ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return ortho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return orthoLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d orthoLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
+ double rm30 = (left + right) / (left - right);
+ double rm31 = (top + bottom) / (bottom - top);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(double, double, double, double, double, double, boolean) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00(2.0 / (right - left)).
+ _m11(2.0 / (top - bottom)).
+ _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)).
+ _m30((right + left) / (left - right)).
+ _m31((top + bottom) / (bottom - top)).
+ _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(double, double, double, double, double, double) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return setOrtho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(double, double, double, double, double, double, boolean) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00(2.0 / (right - left)).
+ _m11(2.0 / (top - bottom)).
+ _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)).
+ _m30((right + left) / (left - right)).
+ _m31((top + bottom) / (bottom - top)).
+ _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return setOrthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, boolean, Matrix4d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrthoSymmetric(width, height, zNear, zFar, zZeroToOne);
+ return orthoSymmetricGeneric(width, height, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d orthoSymmetricGeneric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / width;
+ double rm11 = 2.0 / height;
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m20 * rm32 + m30)
+ ._m31(m21 * rm32 + m31)
+ ._m32(m22 * rm32 + m32)
+ ._m33(m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, Matrix4d dest) {
+ return orthoSymmetric(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, boolean) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ return orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar) {
+ return orthoSymmetric(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, boolean, Matrix4d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrthoSymmetricLH(width, height, zNear, zFar, zZeroToOne);
+ return orthoSymmetricLHGeneric(width, height, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d orthoSymmetricLHGeneric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / width;
+ double rm11 = 2.0 / height;
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m20 * rm32 + m30)
+ ._m31(m21 * rm32 + m31)
+ ._m32(m22 * rm32 + m32)
+ ._m33(m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, Matrix4d dest) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, boolean) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ return orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(double, double, double, double, boolean) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00(2.0 / width).
+ _m11(2.0 / height).
+ _m22((zZeroToOne ? 1.0 : 2.0) / (zNear - zFar)).
+ _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d setOrthoSymmetric(double width, double height, double zNear, double zFar) {
+ return setOrthoSymmetric(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(double, double, double, double, boolean) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00(2.0 / width).
+ _m11(2.0 / height).
+ _m22((zZeroToOne ? 1.0 : 2.0) / (zFar - zNear)).
+ _m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar)).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) {
+ return setOrthoSymmetricLH(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(double, double, double, double) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double, Matrix4d)
+ * @see #setOrtho2D(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d ortho2D(double left, double right, double bottom, double top, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrtho2D(left, right, bottom, top);
+ return ortho2DGeneric(left, right, bottom, top, dest);
+ }
+ private Matrix4d ortho2DGeneric(double left, double right, double bottom, double top, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm30 = (right + left) / (left - right);
+ double rm31 = (top + bottom) / (bottom - top);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(-m20)
+ ._m21(-m21)
+ ._m22(-m22)
+ ._m23(-m23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double)
+ * @see #setOrtho2D(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4d ortho2D(double left, double right, double bottom, double top) {
+ return ortho2D(left, right, bottom, top, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double, Matrix4d)
+ * @see #setOrtho2DLH(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d ortho2DLH(double left, double right, double bottom, double top, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrtho2DLH(left, right, bottom, top);
+ return ortho2DLHGeneric(left, right, bottom, top, dest);
+ }
+ private Matrix4d ortho2DLHGeneric(double left, double right, double bottom, double top, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm30 = (right + left) / (left - right);
+ double rm31 = (top + bottom) / (bottom - top);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double)
+ * @see #setOrtho2DLH(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4d ortho2DLH(double left, double right, double bottom, double top) {
+ return ortho2DLH(left, right, bottom, top, this);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2D(double, double, double, double) ortho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double)
+ * @see #ortho2D(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4d setOrtho2D(double left, double right, double bottom, double top) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00(2.0 / (right - left)).
+ _m11(2.0 / (top - bottom)).
+ _m22(-1.0).
+ _m30((right + left) / (left - right)).
+ _m31((top + bottom) / (bottom - top)).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double)
+ * @see #ortho2DLH(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4d setOrtho2DLH(double left, double right, double bottom, double top) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00(2.0 / (right - left)).
+ _m11(2.0 / (top - bottom)).
+ _m30((right + left) / (left - right)).
+ _m31((top + bottom) / (bottom - top)).
+ properties = PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3dc, Vector3dc, Vector3dc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3dc, Vector3dc) setLookAlong()}.
+ *
+ * @see #lookAlong(double, double, double, double, double, double)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4d lookAlong(Vector3dc dir, Vector3dc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3dc, Vector3dc, Vector3dc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3dc, Vector3dc) setLookAlong()}.
+ *
+ * @see #lookAlong(double, double, double, double, double, double)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAlong(Vector3dc dir, Vector3dc up, Matrix4d dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAlong(dirX, dirY, dirZ, upX, upY, upZ);
+ return lookAlongGeneric(dirX, dirY, dirZ, upX, upY, upZ, dest);
+ }
+
+ private Matrix4d lookAlongGeneric(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4d dest) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+ // perform optimized matrix multiplication
+ // introduce temporaries for dependent results
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ // set the rest of the matrix elements
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d lookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc) setLookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(Vector3dc, Vector3dc)}.
+ *
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ * @see #lookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4d setLookAlong(Vector3dc dir, Vector3dc up) {
+ return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(double, double, double, double, double, double, double, double, double)
+ * setLookAt()} with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()}
+ *
+ * @see #setLookAlong(double, double, double, double, double, double)
+ * @see #lookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d setLookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ _m00(leftX).
+ _m01(upnX).
+ _m02(dirX).
+ _m03(0.0).
+ _m10(leftY).
+ _m11(upnY).
+ _m12(dirY).
+ _m13(0.0).
+ _m20(leftZ).
+ _m21(upnZ).
+ _m22(dirZ).
+ _m23(0.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m32(0.0).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns
+ * -z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(Vector3dc, Vector3dc, Vector3dc) lookAt()}.
+ *
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4d setLookAt(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return setLookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}.
+ *
+ * @see #setLookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d setLookAt(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ return this.
+ _m00(leftX).
+ _m01(upnX).
+ _m02(dirX).
+ _m03(0.0).
+ _m10(leftY).
+ _m11(upnY).
+ _m12(dirY).
+ _m13(0.0).
+ _m20(leftZ).
+ _m21(upnZ).
+ _m22(dirZ).
+ _m23(0.0).
+ _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)).
+ _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)).
+ _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)).
+ _m33(1.0).
+ _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAt(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4d dest) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4d lookAt(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
+ *
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return lookAtPerspective(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4d lookAtGeneric(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4d dest) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+ double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ // introduce temporaries for dependent results
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ // set the rest of the matrix elements
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
+ *
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d lookAt(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ return lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustum(double, double, double, double, double, double) frustum()} or {@link #perspective(double, double, double, double) perspective()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
+ *
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAtPerspective(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4d dest) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ double nm10 = m00 * leftY;
+ double nm20 = m00 * leftZ;
+ double nm21 = m11 * upnZ;
+ double nm30 = m00 * rm30;
+ double nm31 = m11 * rm31;
+ double nm32 = m22 * rm32 + m32;
+ double nm33 = m23 * rm32;
+ return dest
+ ._m00(m00 * leftX)
+ ._m01(m11 * upnX)
+ ._m02(m22 * dirX)
+ ._m03(m23 * dirX)
+ ._m10(nm10)
+ ._m11(m11 * upnY)
+ ._m12(m22 * dirY)
+ ._m13(m23 * dirY)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(m22 * dirZ)
+ ._m23(m23 * dirZ)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns
+ * +z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(Vector3dc, Vector3dc, Vector3dc) lookAt()}.
+ *
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4d setLookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return setLookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}.
+ *
+ * @see #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d setLookAtLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ _m00(leftX).
+ _m01(upnX).
+ _m02(dirX).
+ _m03(0.0).
+ _m10(leftY).
+ _m11(upnY).
+ _m12(dirY).
+ _m13(0.0).
+ _m20(leftZ).
+ _m21(upnZ).
+ _m22(dirZ).
+ _m23(0.0).
+ _m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ)).
+ _m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ)).
+ _m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ)).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4d dest) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4d lookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return lookAtPerspectiveLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4d dest) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+ double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ // introduce temporaries for dependent results
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ // set the rest of the matrix elements
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ return lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustumLH(double, double, double, double, double, double) frustumLH()} or {@link #perspectiveLH(double, double, double, double) perspectiveLH()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
+ *
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d lookAtPerspectiveLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4d dest) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+ double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+
+ double nm00 = m00 * rm00;
+ double nm01 = m11 * rm01;
+ double nm02 = m22 * rm02;
+ double nm03 = m23 * rm02;
+ double nm10 = m00 * rm10;
+ double nm11 = m11 * rm11;
+ double nm12 = m22 * rm12;
+ double nm13 = m23 * rm12;
+ double nm20 = m00 * rm20;
+ double nm21 = m11 * rm21;
+ double nm22 = m22 * rm22;
+ double nm23 = m23 * rm22;
+ double nm30 = m00 * rm30;
+ double nm31 = m11 * rm31;
+ double nm32 = m22 * rm32 + m32;
+ double nm33 = m23 * rm32;
+ dest._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+
+ return dest;
+ }
+
+ /**
+ * This method is equivalent to calling: translate(w-1-2*x, h-1-2*y, 0).scale(w, h, 1)
+ *
+ * If M
is this
matrix and T
the created transformation matrix,
+ * then the new matrix will be M * T
. So when transforming a
+ * vector v
with the new matrix by using M * T * v
, the
+ * created transformation will be applied first!
+ *
+ * @param x
+ * the tile's x coordinate/index (should be in [0..w)
)
+ * @param y
+ * the tile's y coordinate/index (should be in [0..h)
)
+ * @param w
+ * the number of tiles along the x axis
+ * @param h
+ * the number of tiles along the y axis
+ * @return this
+ */
+ public Matrix4d tile(int x, int y, int w, int h) {
+ return tile(x, y, w, h, this);
+ }
+ public Matrix4d tile(int x, int y, int w, int h, Matrix4d dest) {
+ float tx = w - 1 - (x<<1), ty = h - 1 - (y<<1);
+ return dest
+ ._m30(Math.fma(m00, tx, Math.fma(m10, ty, m30)))
+ ._m31(Math.fma(m01, tx, Math.fma(m11, ty, m31)))
+ ._m32(Math.fma(m02, tx, Math.fma(m12, ty, m32)))
+ ._m33(Math.fma(m03, tx, Math.fma(m13, ty, m33)))
+ ._m00(m00 * w)
+ ._m01(m01 * w)
+ ._m02(m02 * w)
+ ._m03(m03 * w)
+ ._m10(m10 * h)
+ ._m11(m11 * h)
+ ._m12(m12 * h)
+ ._m13(m13 * h)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(double, double, double, double, boolean) setPerspective}.
+ *
+ * @see #setPerspective(double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspective(fovy, aspect, zNear, zFar, zZeroToOne);
+ return perspectiveGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d perspectiveGeneric(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ double h = Math.tan(fovy * 0.5);
+ // calculate right matrix elements
+ double rm00 = 1.0 / (h * aspect);
+ double rm11 = 1.0 / h;
+ double rm22;
+ double rm32;
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ rm22 = e - 1.0;
+ rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear;
+ } else if (nearInf) {
+ double e = 1E-6;
+ rm22 = (zZeroToOne ? 0.0 : 1.0) - e;
+ rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ double nm20 = m20 * rm22 - m30;
+ double nm21 = m21 * rm22 - m31;
+ double nm22 = m22 * rm22 - m32;
+ double nm23 = m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(double, double, double, double) setPerspective}.
+ *
+ * @see #setPerspective(double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, Matrix4d dest) {
+ return perspective(fovy, aspect, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(double, double, double, double, boolean) setPerspective}.
+ *
+ * @see #setPerspective(double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne) {
+ return perspective(fovy, aspect, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(double, double, double, double) setPerspective}.
+ *
+ * @see #setPerspective(double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d perspective(double fovy, double aspect, double zNear, double zFar) {
+ return perspective(fovy, aspect, zNear, zFar, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(double, double, double, double, boolean) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(double, double, double, double, boolean)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspectiveRect(width, height, zNear, zFar, zZeroToOne);
+ return perspectiveRectGeneric(width, height, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d perspectiveRectGeneric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ double rm00 = (zNear + zNear) / width;
+ double rm11 = (zNear + zNear) / height;
+ double rm22, rm32;
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6f;
+ rm22 = e - 1.0;
+ rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear;
+ } else if (nearInf) {
+ double e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0 : 1.0) - e;
+ rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ double nm20 = m20 * rm22 - m30;
+ double nm21 = m21 * rm22 - m31;
+ double nm22 = m22 * rm22 - m32;
+ double nm23 = m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(double, double, double, double)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, Matrix4d dest) {
+ return perspectiveRect(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(double, double, double, double, boolean) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(double, double, double, double, boolean)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ return perspectiveRect(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(double, double, double, double) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(double, double, double, double)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d perspectiveRect(double width, double height, double zNear, double zFar) {
+ return perspectiveRect(width, height, zNear, zFar, this);
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, boolean) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(double, double, double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne);
+ return perspectiveOffCenterGeneric(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d perspectiveOffCenterGeneric(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ double h = Math.tan(fovy * 0.5);
+ // calculate right matrix elements
+ double xScale = 1.0 / (h * aspect);
+ double yScale = 1.0 / h;
+ double rm00 = xScale;
+ double rm11 = yScale;
+ double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY);
+ double rm20 = offX * xScale;
+ double rm21 = offY * yScale;
+ double rm22;
+ double rm32;
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ rm22 = e - 1.0;
+ rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear;
+ } else if (nearInf) {
+ double e = 1E-6;
+ rm22 = (zZeroToOne ? 0.0 : 1.0) - e;
+ rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30;
+ double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31;
+ double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32;
+ double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | PROPERTY_ORTHONORMAL | (rm20 == 0.0 && rm21 == 0.0 ? 0 : PROPERTY_PERSPECTIVE)));
+ return dest;
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(double, double, double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, Matrix4d dest) {
+ return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double, boolean) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(double, double, double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, boolean zZeroToOne) {
+ return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(double, double, double, double, double, double) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(double, double, double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar) {
+ return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspective(double, double, double, double, boolean) perspective()}.
+ *
+ * @see #perspective(double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne) {
+ double h = Math.tan(fovy * 0.5);
+ _m00(1.0 / (h * aspect)).
+ _m01(0.0).
+ _m02(0.0).
+ _m03(0.0).
+ _m10(0.0).
+ _m11(1.0 / h).
+ _m12(0.0).
+ _m13(0.0).
+ _m20(0.0).
+ _m21(0.0);
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ _m22(e - 1.0).
+ _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear);
+ } else if (nearInf) {
+ double e = 1E-6;
+ _m22((zZeroToOne ? 0.0 : 1.0) - e).
+ _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar);
+ } else {
+ _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)).
+ _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ _m23(-1.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m33(0.0).
+ properties = PROPERTY_PERSPECTIVE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspective(double, double, double, double) perspective()}.
+ *
+ * @see #perspective(double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d setPerspective(double fovy, double aspect, double zNear, double zFar) {
+ return setPerspective(fovy, aspect, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveRect(double, double, double, double, boolean) perspectiveRect()}.
+ *
+ * @see #perspectiveRect(double, double, double, double, boolean)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ this.zero();
+ this._m00((zNear + zNear) / width);
+ this._m11((zNear + zNear) / height);
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ this._m22(e - 1.0);
+ this._m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear);
+ } else if (nearInf) {
+ double e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0 : 1.0) - e);
+ this._m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar));
+ this._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ this._m23(-1.0);
+ properties = PROPERTY_PERSPECTIVE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveRect(double, double, double, double) perspectiveRect()}.
+ *
+ * @see #perspectiveRect(double, double, double, double)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d setPerspectiveRect(double width, double height, double zNear, double zFar) {
+ return setPerspectiveRect(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed
+ * coordinate system using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}.
+ *
+ * @see #perspectiveOffCenter(double, double, double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY,
+ double aspect, double zNear, double zFar) {
+ return setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false);
+ }
+ /**
+ * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed
+ * coordinate system using the given NDC z range.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveOffCenter(double, double, double, double, double, double) perspectiveOffCenter()}.
+ *
+ * @see #perspectiveOffCenter(double, double, double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setPerspectiveOffCenter(double fovy, double offAngleX, double offAngleY,
+ double aspect, double zNear, double zFar, boolean zZeroToOne) {
+ this.zero();
+ double h = Math.tan(fovy * 0.5);
+ double xScale = 1.0 / (h * aspect), yScale = 1.0 / h;
+ _m00(xScale).
+ _m11(yScale);
+ double offX = Math.tan(offAngleX), offY = Math.tan(offAngleY);
+ _m20(offX * xScale).
+ _m21(offY * yScale);
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ _m22(e - 1.0).
+ _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear);
+ } else if (nearInf) {
+ double e = 1E-6;
+ _m22((zZeroToOne ? 0.0 : 1.0) - e).
+ _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar);
+ } else {
+ _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)).
+ _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ _m23(-1.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m33(0.0).
+ properties = offAngleX == 0.0 && offAngleY == 0.0 ? PROPERTY_PERSPECTIVE : 0;
+ return this;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(double, double, double, double, boolean) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne);
+ return perspectiveLHGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d perspectiveLHGeneric(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ double h = Math.tan(fovy * 0.5);
+ // calculate right matrix elements
+ double rm00 = 1.0 / (h * aspect);
+ double rm11 = 1.0 / h;
+ double rm22;
+ double rm32;
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ rm22 = 1.0 - e;
+ rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear;
+ } else if (nearInf) {
+ double e = 1E-6;
+ rm22 = (zZeroToOne ? 0.0 : 1.0) - e;
+ rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ double nm20 = m20 * rm22 + m30;
+ double nm21 = m21 * rm22 + m31;
+ double nm22 = m22 * rm22 + m32;
+ double nm23 = m23 * rm22 + m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(double, double, double, double, boolean) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne) {
+ return perspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, Matrix4d dest) {
+ return perspectiveLH(fovy, aspect, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(double, double, double, double) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar) {
+ return perspectiveLH(fovy, aspect, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveLH(double, double, double, double, boolean) perspectiveLH()}.
+ *
+ * @see #perspectiveLH(double, double, double, double, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne) {
+ double h = Math.tan(fovy * 0.5);
+ _m00(1.0 / (h * aspect)).
+ _m01(0.0).
+ _m02(0.0).
+ _m03(0.0).
+ _m10(0.0).
+ _m11(1.0 / h).
+ _m12(0.0).
+ _m13(0.0).
+ _m20(0.0).
+ _m21(0.0);
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ _m22(1.0 - e).
+ _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear);
+ } else if (nearInf) {
+ double e = 1E-6;
+ _m22((zZeroToOne ? 0.0 : 1.0) - e).
+ _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar);
+ } else {
+ _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)).
+ _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ _m23(1.0).
+ _m30(0.0).
+ _m31(0.0).
+ _m33(0.0).
+ properties = PROPERTY_PERSPECTIVE;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveLH(double, double, double, double) perspectiveLH()}.
+ *
+ * @see #perspectiveLH(double, double, double, double)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d setPerspectiveLH(double fovy, double aspect, double zNear, double zFar) {
+ return setPerspectiveLH(fovy, aspect, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(double, double, double, double, double, double, boolean) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setFrustum(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return frustumGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d frustumGeneric(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = (zNear + zNear) / (right - left);
+ double rm11 = (zNear + zNear) / (top - bottom);
+ double rm20 = (right + left) / (right - left);
+ double rm21 = (top + bottom) / (top - bottom);
+ double rm22;
+ double rm32;
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ rm22 = e - 1.0;
+ rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear;
+ } else if (nearInf) {
+ double e = 1E-6;
+ rm22 = (zZeroToOne ? 0.0 : 1.0) - e;
+ rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30;
+ double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31;
+ double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32;
+ double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest) {
+ return frustum(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(double, double, double, double, double, double, boolean) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ return frustum(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(double, double, double, double, double, double) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return frustum(left, right, bottom, top, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustum(double, double, double, double, double, double, boolean) frustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustum(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00((zNear + zNear) / (right - left)).
+ _m11((zNear + zNear) / (top - bottom)).
+ _m20((right + left) / (right - left)).
+ _m21((top + bottom) / (top - bottom));
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ _m22(e - 1.0).
+ _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear);
+ } else if (nearInf) {
+ double e = 1E-6;
+ _m22((zZeroToOne ? 0.0 : 1.0) - e).
+ _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar);
+ } else {
+ _m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar)).
+ _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ _m23(-1.0).
+ _m33(0.0).
+ properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustum(double, double, double, double, double, double) frustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustum(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d setFrustum(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return setFrustum(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(double, double, double, double, double, double, boolean) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setFrustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return frustumLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4d frustumLHGeneric(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest) {
+ // calculate right matrix elements
+ double rm00 = (zNear + zNear) / (right - left);
+ double rm11 = (zNear + zNear) / (top - bottom);
+ double rm20 = (right + left) / (right - left);
+ double rm21 = (top + bottom) / (top - bottom);
+ double rm22;
+ double rm32;
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ rm22 = 1.0 - e;
+ rm32 = (e - (zZeroToOne ? 1.0 : 2.0)) * zNear;
+ } else if (nearInf) {
+ double e = 1E-6;
+ rm22 = (zZeroToOne ? 0.0 : 1.0) - e;
+ rm32 = ((zZeroToOne ? 1.0 : 2.0) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30;
+ double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31;
+ double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32;
+ double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(double, double, double, double, double, double, boolean) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ return frustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest) {
+ return frustumLH(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(double, double, double, double, double, double) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return frustumLH(left, right, bottom, top, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustumLH(double, double, double, double, double, double, boolean) frustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustumLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ _identity();
+ _m00((zNear + zNear) / (right - left)).
+ _m11((zNear + zNear) / (top - bottom)).
+ _m20((right + left) / (right - left)).
+ _m21((top + bottom) / (top - bottom));
+ boolean farInf = zFar > 0 && Double.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Double.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ double e = 1E-6;
+ _m22(1.0 - e).
+ _m32((e - (zZeroToOne ? 1.0 : 2.0)) * zNear);
+ } else if (nearInf) {
+ double e = 1E-6;
+ _m22((zZeroToOne ? 0.0 : 1.0) - e).
+ _m32(((zZeroToOne ? 1.0 : 2.0) - e) * zFar);
+ } else {
+ _m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear)).
+ _m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ _m23(1.0).
+ _m33(0.0).
+ properties = this.m20 == 0.0 && this.m21 == 0.0 ? PROPERTY_PERSPECTIVE : 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustumLH(double, double, double, double, double, double) frustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustumLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4d setFrustumLH(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return setFrustumLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to represent a perspective projection equivalent to the given intrinsic camera calibration parameters.
+ * The resulting matrix will be suited for a right-handed coordinate system using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * See: https://en.wikipedia.org/
+ *
+ * Reference: http://ksimek.github.io/
+ *
+ * @param alphaX
+ * specifies the focal length and scale along the X axis
+ * @param alphaY
+ * specifies the focal length and scale along the Y axis
+ * @param gamma
+ * the skew coefficient between the X and Y axis (may be 0
)
+ * @param u0
+ * the X coordinate of the principal point in image/sensor units
+ * @param v0
+ * the Y coordinate of the principal point in image/sensor units
+ * @param imgWidth
+ * the width of the sensor/image image/sensor units
+ * @param imgHeight
+ * the height of the sensor/image image/sensor units
+ * @param near
+ * the distance to the near plane
+ * @param far
+ * the distance to the far plane
+ * @return this
+ */
+ public Matrix4d setFromIntrinsic(double alphaX, double alphaY, double gamma, double u0, double v0, int imgWidth, int imgHeight, double near, double far) {
+ double l00 = 2.0 / imgWidth;
+ double l11 = 2.0 / imgHeight;
+ double l22 = 2.0 / (near - far);
+ this.m00 = l00 * alphaX;
+ this.m01 = 0.0;
+ this.m02 = 0.0;
+ this.m03 = 0.0;
+ this.m10 = l00 * gamma;
+ this.m11 = l11 * alphaY;
+ this.m12 = 0.0;
+ this.m13 = 0.0;
+ this.m20 = l00 * u0 - 1.0;
+ this.m21 = l11 * v0 - 1.0;
+ this.m22 = l22 * -(near + far) + (far + near) / (near - far);
+ this.m23 = -1.0;
+ this.m30 = 0.0;
+ this.m31 = 0.0;
+ this.m32 = l22 * -near * far;
+ this.m33 = 0.0;
+ this.properties = PROPERTY_PERSPECTIVE;
+ return this;
+ }
+
+ public Vector4d frustumPlane(int plane, Vector4d dest) {
+ switch (plane) {
+ case PLANE_NX:
+ dest.set(m03 + m00, m13 + m10, m23 + m20, m33 + m30).normalize3();
+ break;
+ case PLANE_PX:
+ dest.set(m03 - m00, m13 - m10, m23 - m20, m33 - m30).normalize3();
+ break;
+ case PLANE_NY:
+ dest.set(m03 + m01, m13 + m11, m23 + m21, m33 + m31).normalize3();
+ break;
+ case PLANE_PY:
+ dest.set(m03 - m01, m13 - m11, m23 - m21, m33 - m31).normalize3();
+ break;
+ case PLANE_NZ:
+ dest.set(m03 + m02, m13 + m12, m23 + m22, m33 + m32).normalize3();
+ break;
+ case PLANE_PZ:
+ dest.set(m03 - m02, m13 - m12, m23 - m22, m33 - m32).normalize3();
+ break;
+ default:
+ throw new IllegalArgumentException("dest"); //$NON-NLS-1$
+ }
+ return dest;
+ }
+
+ public Vector3d frustumCorner(int corner, Vector3d dest) {
+ double d1, d2, d3;
+ double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z;
+ switch (corner) {
+ case CORNER_NXNYNZ: // left, bottom, near
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_PXNYNZ: // right, bottom, near
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_PXPYNZ: // right, top, near
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_NXPYNZ: // left, top, near
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_PXNYPZ: // right, bottom, far
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ case CORNER_NXNYPZ: // left, bottom, far
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ case CORNER_NXPYPZ: // left, top, far
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ case CORNER_PXPYPZ: // right, top, far
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ default:
+ throw new IllegalArgumentException("corner"); //$NON-NLS-1$
+ }
+ double c23x, c23y, c23z;
+ c23x = n2y * n3z - n2z * n3y;
+ c23y = n2z * n3x - n2x * n3z;
+ c23z = n2x * n3y - n2y * n3x;
+ double c31x, c31y, c31z;
+ c31x = n3y * n1z - n3z * n1y;
+ c31y = n3z * n1x - n3x * n1z;
+ c31z = n3x * n1y - n3y * n1x;
+ double c12x, c12y, c12z;
+ c12x = n1y * n2z - n1z * n2y;
+ c12y = n1z * n2x - n1x * n2z;
+ c12z = n1x * n2y - n1y * n2x;
+ double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z);
+ dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot;
+ dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot;
+ dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot;
+ return dest;
+ }
+
+ public Vector3d perspectiveOrigin(Vector3d dest) {
+ /*
+ * Simply compute the intersection point of the left, right and top frustum plane.
+ */
+ double d1, d2, d3;
+ double n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z;
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 - m00; n2y = m13 - m10; n2z = m23 - m20; d2 = m33 - m30; // right
+ n3x = m03 - m01; n3y = m13 - m11; n3z = m23 - m21; d3 = m33 - m31; // top
+ double c23x, c23y, c23z;
+ c23x = n2y * n3z - n2z * n3y;
+ c23y = n2z * n3x - n2x * n3z;
+ c23z = n2x * n3y - n2y * n3x;
+ double c31x, c31y, c31z;
+ c31x = n3y * n1z - n3z * n1y;
+ c31y = n3z * n1x - n3x * n1z;
+ c31z = n3x * n1y - n3y * n1x;
+ double c12x, c12y, c12z;
+ c12x = n1y * n2z - n1z * n2y;
+ c12y = n1z * n2x - n1x * n2z;
+ c12z = n1x * n2y - n1y * n2x;
+ double invDot = 1.0 / (n1x * c23x + n1y * c23y + n1z * c23z);
+ dest.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot;
+ dest.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot;
+ dest.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot;
+ return dest;
+ }
+
+ public Vector3d perspectiveInvOrigin(Vector3d dest) {
+ double invW = 1.0 / m23;
+ dest.x = m20 * invW;
+ dest.y = m21 * invW;
+ dest.z = m22 * invW;
+ return dest;
+ }
+
+ public double perspectiveFov() {
+ /*
+ * Compute the angle between the bottom and top frustum plane normals.
+ */
+ double n1x, n1y, n1z, n2x, n2y, n2z;
+ n1x = m03 + m01; n1y = m13 + m11; n1z = m23 + m21; // bottom
+ n2x = m01 - m03; n2y = m11 - m13; n2z = m21 - m23; // top
+ double n1len = Math.sqrt(n1x * n1x + n1y * n1y + n1z * n1z);
+ double n2len = Math.sqrt(n2x * n2x + n2y * n2y + n2z * n2z);
+ return Math.acos((n1x * n2x + n1y * n2y + n1z * n2z) / (n1len * n2len));
+ }
+
+ public double perspectiveNear() {
+ return m32 / (m23 + m22);
+ }
+
+ public double perspectiveFar() {
+ return m32 / (m22 - m23);
+ }
+
+ public Vector3d frustumRayDir(double x, double y, Vector3d dest) {
+ /*
+ * This method works by first obtaining the frustum plane normals,
+ * then building the cross product to obtain the corner rays,
+ * and finally bilinearly interpolating to obtain the desired direction.
+ * The code below uses a condense form of doing all this making use
+ * of some mathematical identities to simplify the overall expression.
+ */
+ double a = m10 * m23, b = m13 * m21, c = m10 * m21, d = m11 * m23, e = m13 * m20, f = m11 * m20;
+ double g = m03 * m20, h = m01 * m23, i = m01 * m20, j = m03 * m21, k = m00 * m23, l = m00 * m21;
+ double m = m00 * m13, n = m03 * m11, o = m00 * m11, p = m01 * m13, q = m03 * m10, r = m01 * m10;
+ double m1x, m1y, m1z;
+ m1x = (d + e + f - a - b - c) * (1.0 - y) + (a - b - c + d - e + f) * y;
+ m1y = (j + k + l - g - h - i) * (1.0 - y) + (g - h - i + j - k + l) * y;
+ m1z = (p + q + r - m - n - o) * (1.0 - y) + (m - n - o + p - q + r) * y;
+ double m2x, m2y, m2z;
+ m2x = (b - c - d + e + f - a) * (1.0 - y) + (a + b - c - d - e + f) * y;
+ m2y = (h - i - j + k + l - g) * (1.0 - y) + (g + h - i - j - k + l) * y;
+ m2z = (n - o - p + q + r - m) * (1.0 - y) + (m + n - o - p - q + r) * y;
+ dest.x = m1x * (1.0 - x) + m2x * x;
+ dest.y = m1y * (1.0 - x) + m2y * x;
+ dest.z = m1z * (1.0 - x) + m2z * x;
+ return dest.normalize(dest);
+ }
+
+ public Vector3d positiveZ(Vector3d dir) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalizedPositiveZ(dir);
+ return positiveZGeneric(dir);
+ }
+ private Vector3d positiveZGeneric(Vector3d dir) {
+ return dir.set(m10 * m21 - m11 * m20, m20 * m01 - m21 * m00, m00 * m11 - m01 * m10).normalize();
+ }
+
+ public Vector3d normalizedPositiveZ(Vector3d dir) {
+ return dir.set(m02, m12, m22);
+ }
+
+ public Vector3d positiveX(Vector3d dir) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalizedPositiveX(dir);
+ return positiveXGeneric(dir);
+ }
+ private Vector3d positiveXGeneric(Vector3d dir) {
+ return dir.set(m11 * m22 - m12 * m21, m02 * m21 - m01 * m22, m01 * m12 - m02 * m11).normalize();
+ }
+
+ public Vector3d normalizedPositiveX(Vector3d dir) {
+ return dir.set(m00, m10, m20);
+ }
+
+ public Vector3d positiveY(Vector3d dir) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalizedPositiveY(dir);
+ return positiveYGeneric(dir);
+ }
+ private Vector3d positiveYGeneric(Vector3d dir) {
+ return dir.set(m12 * m20 - m10 * m22, m00 * m22 - m02 * m20, m02 * m10 - m00 * m12).normalize();
+ }
+
+ public Vector3d normalizedPositiveY(Vector3d dir) {
+ return dir.set(m01, m11, m21);
+ }
+
+ public Vector3d originAffine(Vector3d dest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double j = m21 * m32 - m22 * m31;
+ dest.x = -m10 * j + m11 * h - m12 * g;
+ dest.y = m00 * j - m01 * h + m02 * g;
+ dest.z = -m30 * d + m31 * b - m32 * a;
+ return dest;
+ }
+
+ public Vector3d origin(Vector3d dest) {
+ if ((properties & PROPERTY_AFFINE) != 0)
+ return originAffine(dest);
+ return originGeneric(dest);
+ }
+ private Vector3d originGeneric(Vector3d dest) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double c = m00 * m13 - m03 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double e = m01 * m13 - m03 * m11;
+ double f = m02 * m13 - m03 * m12;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double i = m20 * m33 - m23 * m30;
+ double j = m21 * m32 - m22 * m31;
+ double k = m21 * m33 - m23 * m31;
+ double l = m22 * m33 - m23 * m32;
+ double det = a * l - b * k + c * j + d * i - e * h + f * g;
+ double invDet = 1.0 / det;
+ double nm30 = (-m10 * j + m11 * h - m12 * g) * invDet;
+ double nm31 = ( m00 * j - m01 * h + m02 * g) * invDet;
+ double nm32 = (-m30 * d + m31 * b - m32 * a) * invDet;
+ double nm33 = det / ( m20 * d - m21 * b + m22 * a);
+ double x = nm30 * nm33;
+ double y = nm31 * nm33;
+ double z = nm32 * nm33;
+ return dest.set(x, y, z);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4d shadow(Vector4dc light, double a, double b, double c, double d) {
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, this);
+ }
+
+ public Matrix4d shadow(Vector4dc light, double a, double b, double c, double d, Matrix4d dest) {
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) {
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this);
+ }
+
+ public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, Matrix4d dest) {
+ // normalize plane
+ double invPlaneLen = Math.invsqrt(a*a + b*b + c*c);
+ double an = a * invPlaneLen;
+ double bn = b * invPlaneLen;
+ double cn = c * invPlaneLen;
+ double dn = d * invPlaneLen;
+
+ double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW;
+
+ // compute right matrix elements
+ double rm00 = dot - an * lightX;
+ double rm01 = -an * lightY;
+ double rm02 = -an * lightZ;
+ double rm03 = -an * lightW;
+ double rm10 = -bn * lightX;
+ double rm11 = dot - bn * lightY;
+ double rm12 = -bn * lightZ;
+ double rm13 = -bn * lightW;
+ double rm20 = -cn * lightX;
+ double rm21 = -cn * lightY;
+ double rm22 = dot - cn * lightZ;
+ double rm23 = -cn * lightW;
+ double rm30 = -dn * lightX;
+ double rm31 = -dn * lightY;
+ double rm32 = -dn * lightZ;
+ double rm33 = dot - dn * lightW;
+
+ // matrix multiplication
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02 + m33 * rm03;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12 + m33 * rm13;
+ double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23;
+ double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23;
+ double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23;
+ double nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33 * rm23;
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33 * rm33)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ public Matrix4d shadow(Vector4dc light, Matrix4dc planeTransform, Matrix4d dest) {
+ // compute plane equation by transforming (y = 0)
+ double a = planeTransform.m10();
+ double b = planeTransform.m11();
+ double c = planeTransform.m12();
+ double d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4d shadow(Vector4d light, Matrix4d planeTransform) {
+ return shadow(light, planeTransform, this);
+ }
+
+ public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4dc planeTransform, Matrix4d dest) {
+ // compute plane equation by transforming (y = 0)
+ double a = planeTransform.m10();
+ double b = planeTransform.m11();
+ double c = planeTransform.m12();
+ double d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4dc planeTransform) {
+ return shadow(lightX, lightY, lightZ, lightW, planeTransform, this);
+ }
+
+ /**
+ * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
while constraining a cylindrical rotation around the given up
vector.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the rotation axis (must be {@link Vector3d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4d billboardCylindrical(Vector3dc objPos, Vector3dc targetPos, Vector3dc up) {
+ double dirX = targetPos.x() - objPos.x();
+ double dirY = targetPos.y() - objPos.y();
+ double dirZ = targetPos.z() - objPos.z();
+ // left = up x dir
+ double leftX = up.y() * dirZ - up.z() * dirY;
+ double leftY = up.z() * dirX - up.x() * dirZ;
+ double leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // recompute dir by constraining rotation around 'up'
+ // dir = left x up
+ dirX = leftY * up.z() - leftZ * up.y();
+ dirY = leftZ * up.x() - leftX * up.z();
+ dirZ = leftX * up.y() - leftY * up.x();
+ // normalize dir
+ double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // set matrix elements
+ _m00(leftX).
+ _m01(leftY).
+ _m02(leftZ).
+ _m03(0.0).
+ _m10(up.x()).
+ _m11(up.y()).
+ _m12(up.z()).
+ _m13(0.0).
+ _m20(dirX).
+ _m21(dirY).
+ _m22(dirZ).
+ _m23(0.0).
+ _m30(objPos.x()).
+ _m31(objPos.y()).
+ _m32(objPos.z()).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * If preserving an up vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained
+ * using {@link #billboardSpherical(Vector3dc, Vector3dc)}.
+ *
+ * @see #billboardSpherical(Vector3dc, Vector3dc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the up axis used to orient the object
+ * @return this
+ */
+ public Matrix4d billboardSpherical(Vector3dc objPos, Vector3dc targetPos, Vector3dc up) {
+ double dirX = targetPos.x() - objPos.x();
+ double dirY = targetPos.y() - objPos.y();
+ double dirZ = targetPos.z() - objPos.z();
+ // normalize dir
+ double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // left = up x dir
+ double leftX = up.y() * dirZ - up.z() * dirY;
+ double leftY = up.z() * dirX - up.x() * dirZ;
+ double leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // up = dir x left
+ double upX = dirY * leftZ - dirZ * leftY;
+ double upY = dirZ * leftX - dirX * leftZ;
+ double upZ = dirX * leftY - dirY * leftX;
+ // set matrix elements
+ _m00(leftX).
+ _m01(leftY).
+ _m02(leftZ).
+ _m03(0.0).
+ _m10(upX).
+ _m11(upY).
+ _m12(upZ).
+ _m13(0.0).
+ _m20(dirX).
+ _m21(dirY).
+ _m22(dirZ).
+ _m23(0.0).
+ _m30(objPos.x()).
+ _m31(objPos.y()).
+ _m32(objPos.z()).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
using a shortest arc rotation by not preserving any up vector of the object.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * In order to specify an up vector which needs to be maintained when rotating the +Z axis of the object,
+ * use {@link #billboardSpherical(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #billboardSpherical(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @return this
+ */
+ public Matrix4d billboardSpherical(Vector3dc objPos, Vector3dc targetPos) {
+ double toDirX = targetPos.x() - objPos.x();
+ double toDirY = targetPos.y() - objPos.y();
+ double toDirZ = targetPos.z() - objPos.z();
+ double x = -toDirY;
+ double y = toDirX;
+ double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ;
+ double invNorm = Math.invsqrt(x * x + y * y + w * w);
+ x *= invNorm;
+ y *= invNorm;
+ w *= invNorm;
+ double q00 = (x + x) * x;
+ double q11 = (y + y) * y;
+ double q01 = (x + x) * y;
+ double q03 = (x + x) * w;
+ double q13 = (y + y) * w;
+ _m00(1.0 - q11).
+ _m01(q01).
+ _m02(-q13).
+ _m03(0.0).
+ _m10(q01).
+ _m11(1.0 - q00).
+ _m12(q03).
+ _m13(0.0).
+ _m20(q13).
+ _m21(-q03).
+ _m22(1.0 - q11 - q00).
+ _m23(0.0).
+ _m30(objPos.x()).
+ _m31(objPos.y()).
+ _m32(objPos.z()).
+ _m33(1.0).
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(m00);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m01);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m02);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m03);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m10);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m11);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m12);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m13);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m20);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m21);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m22);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m23);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m30);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m31);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m32);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m33);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof Matrix4d))
+ return false;
+ Matrix4d other = (Matrix4d) obj;
+ if (Double.doubleToLongBits(m00) != Double.doubleToLongBits(other.m00))
+ return false;
+ if (Double.doubleToLongBits(m01) != Double.doubleToLongBits(other.m01))
+ return false;
+ if (Double.doubleToLongBits(m02) != Double.doubleToLongBits(other.m02))
+ return false;
+ if (Double.doubleToLongBits(m03) != Double.doubleToLongBits(other.m03))
+ return false;
+ if (Double.doubleToLongBits(m10) != Double.doubleToLongBits(other.m10))
+ return false;
+ if (Double.doubleToLongBits(m11) != Double.doubleToLongBits(other.m11))
+ return false;
+ if (Double.doubleToLongBits(m12) != Double.doubleToLongBits(other.m12))
+ return false;
+ if (Double.doubleToLongBits(m13) != Double.doubleToLongBits(other.m13))
+ return false;
+ if (Double.doubleToLongBits(m20) != Double.doubleToLongBits(other.m20))
+ return false;
+ if (Double.doubleToLongBits(m21) != Double.doubleToLongBits(other.m21))
+ return false;
+ if (Double.doubleToLongBits(m22) != Double.doubleToLongBits(other.m22))
+ return false;
+ if (Double.doubleToLongBits(m23) != Double.doubleToLongBits(other.m23))
+ return false;
+ if (Double.doubleToLongBits(m30) != Double.doubleToLongBits(other.m30))
+ return false;
+ if (Double.doubleToLongBits(m31) != Double.doubleToLongBits(other.m31))
+ return false;
+ if (Double.doubleToLongBits(m32) != Double.doubleToLongBits(other.m32))
+ return false;
+ if (Double.doubleToLongBits(m33) != Double.doubleToLongBits(other.m33))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix4dc m, double delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix4d))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m02, m.m02(), delta))
+ return false;
+ if (!Runtime.equals(m03, m.m03(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m12, m.m12(), delta))
+ return false;
+ if (!Runtime.equals(m13, m.m13(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ if (!Runtime.equals(m22, m.m22(), delta))
+ return false;
+ if (!Runtime.equals(m23, m.m23(), delta))
+ return false;
+ if (!Runtime.equals(m30, m.m30(), delta))
+ return false;
+ if (!Runtime.equals(m31, m.m31(), delta))
+ return false;
+ if (!Runtime.equals(m32, m.m32(), delta))
+ return false;
+ if (!Runtime.equals(m33, m.m33(), delta))
+ return false;
+ return true;
+ }
+
+ public Matrix4d pick(double x, double y, double width, double height, int[] viewport, Matrix4d dest) {
+ double sx = viewport[2] / width;
+ double sy = viewport[3] / height;
+ double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
+ double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
+ dest._m30(m00 * tx + m10 * ty + m30)
+ ._m31(m01 * tx + m11 * ty + m31)
+ ._m32(m02 * tx + m12 * ty + m32)
+ ._m33(m03 * tx + m13 * ty + m33)
+ ._m00(m00 * sx)
+ ._m01(m01 * sx)
+ ._m02(m02 * sx)
+ ._m03(m03 * sx)
+ ._m10(m10 * sy)
+ ._m11(m11 * sy)
+ ._m12(m12 * sy)
+ ._m13(m13 * sy)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @return this
+ */
+ public Matrix4d pick(double x, double y, double width, double height, int[] viewport) {
+ return pick(x, y, width, height, viewport, this);
+ }
+
+ public boolean isAffine() {
+ return m03 == 0.0 && m13 == 0.0 && m23 == 0.0 && m33 == 1.0;
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix4d swap(Matrix4d other) {
+ double tmp;
+ tmp = m00; m00 = other.m00; other.m00 = tmp;
+ tmp = m01; m01 = other.m01; other.m01 = tmp;
+ tmp = m02; m02 = other.m02; other.m02 = tmp;
+ tmp = m03; m03 = other.m03; other.m03 = tmp;
+ tmp = m10; m10 = other.m10; other.m10 = tmp;
+ tmp = m11; m11 = other.m11; other.m11 = tmp;
+ tmp = m12; m12 = other.m12; other.m12 = tmp;
+ tmp = m13; m13 = other.m13; other.m13 = tmp;
+ tmp = m20; m20 = other.m20; other.m20 = tmp;
+ tmp = m21; m21 = other.m21; other.m21 = tmp;
+ tmp = m22; m22 = other.m22; other.m22 = tmp;
+ tmp = m23; m23 = other.m23; other.m23 = tmp;
+ tmp = m30; m30 = other.m30; other.m30 = tmp;
+ tmp = m31; m31 = other.m31; other.m31 = tmp;
+ tmp = m32; m32 = other.m32; other.m32 = tmp;
+ tmp = m33; m33 = other.m33; other.m33 = tmp;
+ int props = properties;
+ this.properties = other.properties;
+ other.properties = props;
+ return this;
+ }
+
+ public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, Matrix4d dest) {
+ double m30 = m20 * -radius + this.m30;
+ double m31 = m21 * -radius + this.m31;
+ double m32 = m22 * -radius + this.m32;
+ double m33 = m23 * -radius + this.m33;
+ double sin = Math.sin(angleX);
+ double cos = Math.cosFromSin(sin, angleX);
+ double nm10 = m10 * cos + m20 * sin;
+ double nm11 = m11 * cos + m21 * sin;
+ double nm12 = m12 * cos + m22 * sin;
+ double nm13 = m13 * cos + m23 * sin;
+ double m20 = this.m20 * cos - m10 * sin;
+ double m21 = this.m21 * cos - m11 * sin;
+ double m22 = this.m22 * cos - m12 * sin;
+ double m23 = this.m23 * cos - m13 * sin;
+ sin = Math.sin(angleY);
+ cos = Math.cosFromSin(sin, angleY);
+ double nm00 = m00 * cos - m20 * sin;
+ double nm01 = m01 * cos - m21 * sin;
+ double nm02 = m02 * cos - m22 * sin;
+ double nm03 = m03 * cos - m23 * sin;
+ double nm20 = m00 * sin + m20 * cos;
+ double nm21 = m01 * sin + m21 * cos;
+ double nm22 = m02 * sin + m22 * cos;
+ double nm23 = m03 * sin + m23 * cos;
+ dest._m30(-nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30)
+ ._m31(-nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31)
+ ._m32(-nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32)
+ ._m33(-nm03 * centerX - nm13 * centerY - nm23 * centerZ + m33)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ public Matrix4d arcball(double radius, Vector3dc center, double angleX, double angleY, Matrix4d dest) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, dest);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) {
+ return arcball(radius, centerX, centerY, centerZ, angleX, angleY, this);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4d arcball(double radius, Vector3dc center, double angleX, double angleY) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, this);
+ }
+
+ /**
+ * Compute the axis-aligned bounding box of the frustum described by this
matrix and store the minimum corner
+ * coordinates in the given min
and the maximum corner coordinates in the given max
vector.
+ *
+ * The matrix this
is assumed to be the {@link #invert() inverse} of the origial view-projection matrix
+ * for which to compute the axis-aligned bounding box in world-space.
+ *
+ * The axis-aligned bounding box of the unit frustum is (-1, -1, -1)
, (1, 1, 1)
.
+ *
+ * @param min
+ * will hold the minimum corner coordinates of the axis-aligned bounding box
+ * @param max
+ * will hold the maximum corner coordinates of the axis-aligned bounding box
+ * @return this
+ */
+ public Matrix4d frustumAabb(Vector3d min, Vector3d max) {
+ double minX = Double.POSITIVE_INFINITY;
+ double minY = Double.POSITIVE_INFINITY;
+ double minZ = Double.POSITIVE_INFINITY;
+ double maxX = Double.NEGATIVE_INFINITY;
+ double maxY = Double.NEGATIVE_INFINITY;
+ double maxZ = Double.NEGATIVE_INFINITY;
+ for (int t = 0; t < 8; t++) {
+ double x = ((t & 1) << 1) - 1.0;
+ double y = (((t >>> 1) & 1) << 1) - 1.0;
+ double z = (((t >>> 2) & 1) << 1) - 1.0;
+ double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33);
+ double nx = (m00 * x + m10 * y + m20 * z + m30) * invW;
+ double ny = (m01 * x + m11 * y + m21 * z + m31) * invW;
+ double nz = (m02 * x + m12 * y + m22 * z + m32) * invW;
+ minX = minX < nx ? minX : nx;
+ minY = minY < ny ? minY : ny;
+ minZ = minZ < nz ? minZ : nz;
+ maxX = maxX > nx ? maxX : nx;
+ maxY = maxY > ny ? maxY : ny;
+ maxZ = maxZ > nz ? maxZ : nz;
+ }
+ min.x = minX;
+ min.y = minY;
+ min.z = minZ;
+ max.x = maxX;
+ max.y = maxY;
+ max.z = maxZ;
+ return this;
+ }
+
+ public Matrix4d projectedGridRange(Matrix4dc projector, double sLower, double sUpper, Matrix4d dest) {
+ // Compute intersection with frustum edges and plane
+ double minX = Double.POSITIVE_INFINITY, minY = Double.POSITIVE_INFINITY;
+ double maxX = Double.NEGATIVE_INFINITY, maxY = Double.NEGATIVE_INFINITY;
+ boolean intersection = false;
+ for (int t = 0; t < 3 * 4; t++) {
+ double c0X, c0Y, c0Z;
+ double c1X, c1Y, c1Z;
+ if (t < 4) {
+ // all x edges
+ c0X = -1; c1X = +1;
+ c0Y = c1Y = ((t & 1) << 1) - 1.0;
+ c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0;
+ } else if (t < 8) {
+ // all y edges
+ c0Y = -1; c1Y = +1;
+ c0X = c1X = ((t & 1) << 1) - 1.0;
+ c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0;
+ } else {
+ // all z edges
+ c0Z = -1; c1Z = +1;
+ c0X = c1X = ((t & 1) << 1) - 1.0;
+ c0Y = c1Y = (((t >>> 1) & 1) << 1) - 1.0;
+ }
+ // unproject corners
+ double invW = 1.0 / (m03 * c0X + m13 * c0Y + m23 * c0Z + m33);
+ double p0x = (m00 * c0X + m10 * c0Y + m20 * c0Z + m30) * invW;
+ double p0y = (m01 * c0X + m11 * c0Y + m21 * c0Z + m31) * invW;
+ double p0z = (m02 * c0X + m12 * c0Y + m22 * c0Z + m32) * invW;
+ invW = 1.0 / (m03 * c1X + m13 * c1Y + m23 * c1Z + m33);
+ double p1x = (m00 * c1X + m10 * c1Y + m20 * c1Z + m30) * invW;
+ double p1y = (m01 * c1X + m11 * c1Y + m21 * c1Z + m31) * invW;
+ double p1z = (m02 * c1X + m12 * c1Y + m22 * c1Z + m32) * invW;
+ double dirX = p1x - p0x;
+ double dirY = p1y - p0y;
+ double dirZ = p1z - p0z;
+ double invDenom = 1.0 / dirY;
+ // test for intersection
+ for (int s = 0; s < 2; s++) {
+ double isectT = -(p0y + (s == 0 ? sLower : sUpper)) * invDenom;
+ if (isectT >= 0.0 && isectT <= 1.0) {
+ intersection = true;
+ // project with projector matrix
+ double ix = p0x + isectT * dirX;
+ double iz = p0z + isectT * dirZ;
+ invW = 1.0 / (projector.m03() * ix + projector.m23() * iz + projector.m33());
+ double px = (projector.m00() * ix + projector.m20() * iz + projector.m30()) * invW;
+ double py = (projector.m01() * ix + projector.m21() * iz + projector.m31()) * invW;
+ minX = minX < px ? minX : px;
+ minY = minY < py ? minY : py;
+ maxX = maxX > px ? maxX : px;
+ maxY = maxY > py ? maxY : py;
+ }
+ }
+ }
+ if (!intersection)
+ return null; // <- projected grid is not visible
+ dest.set(maxX - minX, 0, 0, 0, 0, maxY - minY, 0, 0, 0, 0, 1, 0, minX, minY, 0, 1)
+ ._properties(PROPERTY_AFFINE);
+ return dest;
+ }
+
+ public Matrix4d perspectiveFrustumSlice(double near, double far, Matrix4d dest) {
+ double invOldNear = (m23 + m22) / m32;
+ double invNearFar = 1.0 / (near - far);
+ dest._m00(m00 * invOldNear * near)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(m11 * invOldNear * near)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22((far + near) * invNearFar)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32((far + far) * near * invNearFar)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ public Matrix4d orthoCrop(Matrix4dc view, Matrix4d dest) {
+ // determine min/max world z and min/max orthographically view-projected x/y
+ double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY;
+ double minY = Double.POSITIVE_INFINITY, maxY = Double.NEGATIVE_INFINITY;
+ double minZ = Double.POSITIVE_INFINITY, maxZ = Double.NEGATIVE_INFINITY;
+ for (int t = 0; t < 8; t++) {
+ double x = ((t & 1) << 1) - 1.0;
+ double y = (((t >>> 1) & 1) << 1) - 1.0;
+ double z = (((t >>> 2) & 1) << 1) - 1.0;
+ double invW = 1.0 / (m03 * x + m13 * y + m23 * z + m33);
+ double wx = (m00 * x + m10 * y + m20 * z + m30) * invW;
+ double wy = (m01 * x + m11 * y + m21 * z + m31) * invW;
+ double wz = (m02 * x + m12 * y + m22 * z + m32) * invW;
+ invW = 1.0 / (view.m03() * wx + view.m13() * wy + view.m23() * wz + view.m33());
+ double vx = view.m00() * wx + view.m10() * wy + view.m20() * wz + view.m30();
+ double vy = view.m01() * wx + view.m11() * wy + view.m21() * wz + view.m31();
+ double vz = (view.m02() * wx + view.m12() * wy + view.m22() * wz + view.m32()) * invW;
+ minX = minX < vx ? minX : vx;
+ maxX = maxX > vx ? maxX : vx;
+ minY = minY < vy ? minY : vy;
+ maxY = maxY > vy ? maxY : vy;
+ minZ = minZ < vz ? minZ : vz;
+ maxZ = maxZ > vz ? maxZ : vz;
+ }
+ // build crop projection matrix to fit 'this' frustum into view
+ return dest.setOrtho(minX, maxX, minY, maxY, -maxZ, -minZ);
+ }
+
+ /**
+ * Set this
matrix to a perspective transformation that maps the trapezoid spanned by the four corner coordinates
+ * (p0x, p0y)
, (p1x, p1y)
, (p2x, p2y)
and (p3x, p3y)
to the unit square [(-1, -1)..(+1, +1)]
.
+ *
+ * The corner coordinates are given in counter-clockwise order starting from the left corner on the smaller parallel side of the trapezoid
+ * seen when looking at the trapezoid oriented with its shorter parallel edge at the bottom and its longer parallel edge at the top.
+ *
+ * Reference: Trapezoidal Shadow Maps (TSM) - Recipe
+ *
+ * @param p0x
+ * the x coordinate of the left corner at the shorter edge of the trapezoid
+ * @param p0y
+ * the y coordinate of the left corner at the shorter edge of the trapezoid
+ * @param p1x
+ * the x coordinate of the right corner at the shorter edge of the trapezoid
+ * @param p1y
+ * the y coordinate of the right corner at the shorter edge of the trapezoid
+ * @param p2x
+ * the x coordinate of the right corner at the longer edge of the trapezoid
+ * @param p2y
+ * the y coordinate of the right corner at the longer edge of the trapezoid
+ * @param p3x
+ * the x coordinate of the left corner at the longer edge of the trapezoid
+ * @param p3y
+ * the y coordinate of the left corner at the longer edge of the trapezoid
+ * @return this
+ */
+ public Matrix4d trapezoidCrop(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y, double p3x, double p3y) {
+ double aX = p1y - p0y, aY = p0x - p1x;
+ double nm00 = aY;
+ double nm10 = -aX;
+ double nm30 = aX * p0y - aY * p0x;
+ double nm01 = aX;
+ double nm11 = aY;
+ double nm31 = -(aX * p0x + aY * p0y);
+ double c3x = nm00 * p3x + nm10 * p3y + nm30;
+ double c3y = nm01 * p3x + nm11 * p3y + nm31;
+ double s = -c3x / c3y;
+ nm00 += s * nm01;
+ nm10 += s * nm11;
+ nm30 += s * nm31;
+ double d1x = nm00 * p1x + nm10 * p1y + nm30;
+ double d2x = nm00 * p2x + nm10 * p2y + nm30;
+ double d = d1x * c3y / (d2x - d1x);
+ nm31 += d;
+ double sx = 2.0 / d2x;
+ double sy = 1.0 / (c3y + d);
+ double u = (sy + sy) * d / (1.0 - sy * d);
+ double m03 = nm01 * sy;
+ double m13 = nm11 * sy;
+ double m33 = nm31 * sy;
+ nm01 = (u + 1.0) * m03;
+ nm11 = (u + 1.0) * m13;
+ nm31 = (u + 1.0) * m33 - u;
+ nm00 = sx * nm00 - m03;
+ nm10 = sx * nm10 - m13;
+ nm30 = sx * nm30 - m33;
+ set(nm00, nm01, 0, m03,
+ nm10, nm11, 0, m13,
+ 0, 0, 1, 0,
+ nm30, nm31, 0, m33);
+ properties = 0;
+ return this;
+ }
+
+ public Matrix4d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector3d outMin, Vector3d outMax) {
+ double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX;
+ double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX;
+ double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY;
+ double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY;
+ double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ;
+ double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ;
+ double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz;
+ double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz;
+ if (xax < xbx) {
+ xminx = xax;
+ xmaxx = xbx;
+ } else {
+ xminx = xbx;
+ xmaxx = xax;
+ }
+ if (xay < xby) {
+ xminy = xay;
+ xmaxy = xby;
+ } else {
+ xminy = xby;
+ xmaxy = xay;
+ }
+ if (xaz < xbz) {
+ xminz = xaz;
+ xmaxz = xbz;
+ } else {
+ xminz = xbz;
+ xmaxz = xaz;
+ }
+ if (yax < ybx) {
+ yminx = yax;
+ ymaxx = ybx;
+ } else {
+ yminx = ybx;
+ ymaxx = yax;
+ }
+ if (yay < yby) {
+ yminy = yay;
+ ymaxy = yby;
+ } else {
+ yminy = yby;
+ ymaxy = yay;
+ }
+ if (yaz < ybz) {
+ yminz = yaz;
+ ymaxz = ybz;
+ } else {
+ yminz = ybz;
+ ymaxz = yaz;
+ }
+ if (zax < zbx) {
+ zminx = zax;
+ zmaxx = zbx;
+ } else {
+ zminx = zbx;
+ zmaxx = zax;
+ }
+ if (zay < zby) {
+ zminy = zay;
+ zmaxy = zby;
+ } else {
+ zminy = zby;
+ zmaxy = zay;
+ }
+ if (zaz < zbz) {
+ zminz = zaz;
+ zmaxz = zbz;
+ } else {
+ zminz = zbz;
+ zmaxz = zaz;
+ }
+ outMin.x = xminx + yminx + zminx + m30;
+ outMin.y = xminy + yminy + zminy + m31;
+ outMin.z = xminz + yminz + zminz + m32;
+ outMax.x = xmaxx + ymaxx + zmaxx + m30;
+ outMax.y = xmaxy + ymaxy + zmaxy + m31;
+ outMax.z = xmaxz + ymaxz + zmaxz + m32;
+ return this;
+ }
+
+ public Matrix4d transformAab(Vector3dc min, Vector3dc max, Vector3d outMin, Vector3d outMax) {
+ return transformAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), outMin, outMax);
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix4d lerp(Matrix4dc other, double t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix4d lerp(Matrix4dc other, double t, Matrix4d dest) {
+ dest._m00(Math.fma(other.m00() - m00, t, m00))
+ ._m01(Math.fma(other.m01() - m01, t, m01))
+ ._m02(Math.fma(other.m02() - m02, t, m02))
+ ._m03(Math.fma(other.m03() - m03, t, m03))
+ ._m10(Math.fma(other.m10() - m10, t, m10))
+ ._m11(Math.fma(other.m11() - m11, t, m11))
+ ._m12(Math.fma(other.m12() - m12, t, m12))
+ ._m13(Math.fma(other.m13() - m13, t, m13))
+ ._m20(Math.fma(other.m20() - m20, t, m20))
+ ._m21(Math.fma(other.m21() - m21, t, m21))
+ ._m22(Math.fma(other.m22() - m22, t, m22))
+ ._m23(Math.fma(other.m23() - m23, t, m23))
+ ._m30(Math.fma(other.m30() - m30, t, m30))
+ ._m31(Math.fma(other.m31() - m31, t, m31))
+ ._m32(Math.fma(other.m32() - m32, t, m32))
+ ._m33(Math.fma(other.m33() - m33, t, m33))
+ ._properties(properties & other.properties());
+ return dest;
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3dc, Vector3dc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine(), dest)
+ *
+ * @see #rotateTowards(double, double, double, double, double, double, Matrix4d)
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ *
+ * @param direction
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateTowards(Vector3dc direction, Vector3dc up, Matrix4d dest) {
+ return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3dc, Vector3dc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine())
+ *
+ * @see #rotateTowards(double, double, double, double, double, double)
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ *
+ * @param direction
+ * the direction to orient towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4d rotateTowards(Vector3dc direction, Vector3dc up) {
+ return rotateTowards(direction.x(), direction.y(), direction.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine())
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4d dest) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ double rm00 = leftX;
+ double rm01 = leftY;
+ double rm02 = leftZ;
+ double rm10 = upnX;
+ double rm11 = upnY;
+ double rm12 = upnZ;
+ double rm20 = ndirX;
+ double rm21 = ndirY;
+ double rm22 = ndirZ;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ double nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with dir
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine()
+ *
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ * @see #rotateTowards(double, double, double, double, double, double)
+ *
+ * @param dir
+ * the direction to orient the local -z axis towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4d rotationTowards(Vector3dc dir, Vector3dc up) {
+ return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with dir
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine()
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this._identity();
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given pos
and aligns the local -z
+ * axis with dir
.
+ *
+ * This method is equivalent to calling: translation(pos).rotateTowards(dir, up)
+ *
+ * @see #translation(Vector3dc)
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ *
+ * @param pos
+ * the position to translate to
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4d translationRotateTowards(Vector3dc pos, Vector3dc dir, Vector3dc up) {
+ return translationRotateTowards(pos.x(), pos.y(), pos.z(), dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given (posX, posY, posZ)
and aligns the local -z
+ * axis with (dirX, dirY, dirZ)
.
+ *
+ * This method is equivalent to calling: translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotateTowards(double, double, double, double, double, double)
+ *
+ * @param posX
+ * the x-coordinate of the position to translate to
+ * @param posY
+ * the y-coordinate of the position to translate to
+ * @param posZ
+ * the z-coordinate of the position to translate to
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m03 = 0.0;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m13 = 0.0;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ this.m23 = 0.0;
+ this.m30 = posX;
+ this.m31 = posY;
+ this.m32 = posZ;
+ this.m33 = 1.0;
+ properties = PROPERTY_AFFINE | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ public Vector3d getEulerAnglesZYX(Vector3d dest) {
+ dest.x = Math.atan2(m12, m22);
+ dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02));
+ dest.z = Math.atan2(m01, m00);
+ return dest;
+ }
+
+ public Vector3d getEulerAnglesXYZ(Vector3d dest) {
+ dest.x = Math.atan2(-m21, m22);
+ dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20));
+ dest.z = Math.atan2(-m10, m00);
+ return dest;
+ }
+
+ /**
+ * Compute the extents of the coordinate system before this {@link #isAffine() affine} transformation was applied
+ * and store the resulting corner coordinates in corner
and the span vectors in
+ * xDir
, yDir
and zDir
.
+ *
+ * That means, given the maximum extents of the coordinate system between [-1..+1]
in all dimensions,
+ * this method returns one corner and the length and direction of the three base axis vectors in the coordinate
+ * system before this transformation is applied, which transforms into the corner coordinates [-1, +1]
.
+ *
+ * This method is equivalent to computing at least three adjacent corners using {@link #frustumCorner(int, Vector3d)}
+ * and subtracting them to obtain the length and direction of the span vectors.
+ *
+ * @param corner
+ * will hold one corner of the span (usually the corner {@link Matrix4dc#CORNER_NXNYNZ})
+ * @param xDir
+ * will hold the direction and length of the span along the positive X axis
+ * @param yDir
+ * will hold the direction and length of the span along the positive Y axis
+ * @param zDir
+ * will hold the direction and length of the span along the positive z axis
+ * @return this
+ */
+ public Matrix4d affineSpan(Vector3d corner, Vector3d xDir, Vector3d yDir, Vector3d zDir) {
+ double a = m10 * m22, b = m10 * m21, c = m10 * m02, d = m10 * m01;
+ double e = m11 * m22, f = m11 * m20, g = m11 * m02, h = m11 * m00;
+ double i = m12 * m21, j = m12 * m20, k = m12 * m01, l = m12 * m00;
+ double m = m20 * m02, n = m20 * m01, o = m21 * m02, p = m21 * m00;
+ double q = m22 * m01, r = m22 * m00;
+ double s = 1.0 / (m00 * m11 - m01 * m10) * m22 + (m02 * m10 - m00 * m12) * m21 + (m01 * m12 - m02 * m11) * m20;
+ double nm00 = (e - i) * s, nm01 = (o - q) * s, nm02 = (k - g) * s;
+ double nm10 = (j - a) * s, nm11 = (r - m) * s, nm12 = (c - l) * s;
+ double nm20 = (b - f) * s, nm21 = (n - p) * s, nm22 = (h - d) * s;
+ corner.x = -nm00 - nm10 - nm20 + (a * m31 - b * m32 + f * m32 - e * m30 + i * m30 - j * m31) * s;
+ corner.y = -nm01 - nm11 - nm21 + (m * m31 - n * m32 + p * m32 - o * m30 + q * m30 - r * m31) * s;
+ corner.z = -nm02 - nm12 - nm22 + (g * m30 - k * m30 + l * m31 - c * m31 + d * m32 - h * m32) * s;
+ xDir.x = 2.0 * nm00; xDir.y = 2.0 * nm01; xDir.z = 2.0 * nm02;
+ yDir.x = 2.0 * nm10; yDir.y = 2.0 * nm11; yDir.z = 2.0 * nm12;
+ zDir.x = 2.0 * nm20; zDir.y = 2.0 * nm21; zDir.z = 2.0 * nm22;
+ return this;
+ }
+
+ public boolean testPoint(double x, double y, double z) {
+ double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30;
+ double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30;
+ double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31;
+ double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31;
+ double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32;
+ double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32;
+ return nxX * x + nxY * y + nxZ * z + nxW >= 0 && pxX * x + pxY * y + pxZ * z + pxW >= 0 &&
+ nyX * x + nyY * y + nyZ * z + nyW >= 0 && pyX * x + pyY * y + pyZ * z + pyW >= 0 &&
+ nzX * x + nzY * y + nzZ * z + nzW >= 0 && pzX * x + pzY * y + pzZ * z + pzW >= 0;
+ }
+
+ public boolean testSphere(double x, double y, double z, double r) {
+ double invl;
+ double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30;
+ invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ);
+ nxX *= invl; nxY *= invl; nxZ *= invl; nxW *= invl;
+ double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30;
+ invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ);
+ pxX *= invl; pxY *= invl; pxZ *= invl; pxW *= invl;
+ double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31;
+ invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ);
+ nyX *= invl; nyY *= invl; nyZ *= invl; nyW *= invl;
+ double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31;
+ invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ);
+ pyX *= invl; pyY *= invl; pyZ *= invl; pyW *= invl;
+ double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32;
+ invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ);
+ nzX *= invl; nzY *= invl; nzZ *= invl; nzW *= invl;
+ double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32;
+ invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ);
+ pzX *= invl; pzY *= invl; pzZ *= invl; pzW *= invl;
+ return nxX * x + nxY * y + nxZ * z + nxW >= -r && pxX * x + pxY * y + pxZ * z + pxW >= -r &&
+ nyX * x + nyY * y + nyZ * z + nyW >= -r && pyX * x + pyY * y + pyZ * z + pyW >= -r &&
+ nzX * x + nzY * y + nzZ * z + nzW >= -r && pzX * x + pzY * y + pzZ * z + pzW >= -r;
+ }
+
+ public boolean testAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
+ double nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30;
+ double pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30;
+ double nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31;
+ double pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31;
+ double nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32;
+ double pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32;
+ /*
+ * This is an implementation of the "2.4 Basic intersection test" of the mentioned site.
+ * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted.
+ */
+ return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW &&
+ pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW &&
+ nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW &&
+ pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW &&
+ nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW &&
+ pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @return this
+ */
+ public Matrix4d obliqueZ(double a, double b) {
+ this.m20 = m00 * a + m10 * b + m20;
+ this.m21 = m01 * a + m11 * b + m21;
+ this.m22 = m02 * a + m12 * b + m22;
+ this.properties &= PROPERTY_AFFINE;
+ return this;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4d obliqueZ(double a, double b, Matrix4d dest) {
+ dest._m00(m00)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(m11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(m00 * a + m10 * b + m20)
+ ._m21(m01 * a + m11 * b + m21)
+ ._m22(m02 * a + m12 * b + m22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & PROPERTY_AFFINE);
+ return dest;
+ }
+
+ /**
+ * Create a view and projection matrix from a given eye
position, a given bottom left corner position p
of the near plane rectangle
+ * and the extents of the near plane rectangle along its local x
and y
axes, and store the resulting matrices
+ * in projDest
and viewDest
.
+ *
+ * This method creates a view and perspective projection matrix assuming that there is a pinhole camera at position eye
+ * projecting the scene onto the near plane defined by the rectangle.
+ *
+ * All positions and lengths are in the same (world) unit.
+ *
+ * @param eye
+ * the position of the camera
+ * @param p
+ * the bottom left corner of the near plane rectangle (will map to the bottom left corner in window coordinates)
+ * @param x
+ * the direction and length of the local "bottom/top" X axis/side of the near plane rectangle
+ * @param y
+ * the direction and length of the local "left/right" Y axis/side of the near plane rectangle
+ * @param nearFarDist
+ * the distance between the far and near plane (the near plane will be calculated by this method).
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * If the special value {@link Double#NEGATIVE_INFINITY} is used, the near and far planes will be swapped and
+ * the near clipping plane will be at positive infinity.
+ * If a negative value is used (except for {@link Double#NEGATIVE_INFINITY}) the near and far planes will be swapped
+ * @param zeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param projDest
+ * will hold the resulting projection matrix
+ * @param viewDest
+ * will hold the resulting view matrix
+ */
+ public static void projViewFromRectangle(
+ Vector3d eye, Vector3d p, Vector3d x, Vector3d y, double nearFarDist, boolean zeroToOne,
+ Matrix4d projDest, Matrix4d viewDest) {
+ double zx = y.y * x.z - y.z * x.y, zy = y.z * x.x - y.x * x.z, zz = y.x * x.y - y.y * x.x;
+ double zd = zx * (p.x - eye.x) + zy * (p.y - eye.y) + zz * (p.z - eye.z);
+ double zs = zd >= 0 ? 1 : -1; zx *= zs; zy *= zs; zz *= zs; zd *= zs;
+ viewDest.setLookAt(eye.x, eye.y, eye.z, eye.x + zx, eye.y + zy, eye.z + zz, y.x, y.y, y.z);
+ double px = viewDest.m00 * p.x + viewDest.m10 * p.y + viewDest.m20 * p.z + viewDest.m30;
+ double py = viewDest.m01 * p.x + viewDest.m11 * p.y + viewDest.m21 * p.z + viewDest.m31;
+ double tx = viewDest.m00 * x.x + viewDest.m10 * x.y + viewDest.m20 * x.z;
+ double ty = viewDest.m01 * y.x + viewDest.m11 * y.y + viewDest.m21 * y.z;
+ double len = Math.sqrt(zx * zx + zy * zy + zz * zz);
+ double near = zd / len, far;
+ if (Double.isInfinite(nearFarDist) && nearFarDist < 0.0) {
+ far = near;
+ near = Double.POSITIVE_INFINITY;
+ } else if (Double.isInfinite(nearFarDist) && nearFarDist > 0.0) {
+ far = Double.POSITIVE_INFINITY;
+ } else if (nearFarDist < 0.0) {
+ far = near;
+ near = near + nearFarDist;
+ } else {
+ far = near + nearFarDist;
+ }
+ projDest.setFrustum(px, px + tx, py, py + ty, near, far, zeroToOne);
+ }
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3d)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3d)}) and the
+ * given vector up
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from
+ * {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc)} called with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3d)}), the sum of this position and the
+ * negated local Z axis as well as the given vector up
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4d withLookAtUp(Vector3dc up) {
+ return withLookAtUp(up.x(), up.y(), up.z(), this);
+ }
+
+ public Matrix4d withLookAtUp(Vector3dc up, Matrix4d dest) {
+ return withLookAtUp(up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3d)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3d)}) and the
+ * given vector (upX, upY, upZ)
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from
+ * {@link #setLookAt(double, double, double, double, double, double, double, double, double)} called with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3d)}), the sum of this position and the
+ * negated local Z axis as well as the given vector (upX, upY, upZ)
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param upX
+ * the x coordinate of the up vector
+ * @param upY
+ * the y coordinate of the up vector
+ * @param upZ
+ * the z coordinate of the up vector
+ * @return this
+ */
+ public Matrix4d withLookAtUp(double upX, double upY, double upZ) {
+ return withLookAtUp(upX, upY, upZ, this);
+ }
+
+ public Matrix4d withLookAtUp(double upX, double upY, double upZ, Matrix4d dest) {
+ double y = (upY * m21 - upZ * m11) * m02 +
+ (upZ * m01 - upX * m21) * m12 +
+ (upX * m11 - upY * m01) * m22;
+ double x = upX * m01 + upY * m11 + upZ * m21;
+ if ((properties & PROPERTY_ORTHONORMAL) == 0)
+ x *= Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21);
+ double invsqrt = Math.invsqrt(y * y + x * x);
+ double c = x * invsqrt, s = y * invsqrt;
+ double nm00 = c * m00 - s * m01, nm10 = c * m10 - s * m11, nm20 = c * m20 - s * m21, nm31 = s * m30 + c * m31;
+ double nm01 = s * m00 + c * m01, nm11 = s * m10 + c * m11, nm21 = s * m20 + c * m21, nm30 = c * m30 - s * m31;
+ dest._m00(nm00)._m10(nm10)._m20(nm20)._m30(nm30)
+ ._m01(nm01)._m11(nm11)._m21(nm21)._m31(nm31);
+ if (dest != this) {
+ dest
+ ._m02(m02)._m12(m12)._m22(m22)._m32(m32)
+ ._m03(m03)._m13(m13)._m23(m23)._m33(m33);
+ }
+ dest._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapXZY() {
+ return mapXZY(this);
+ }
+ public Matrix4d mapXZY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapXZnY() {
+ return mapXZnY(this);
+ }
+ public Matrix4d mapXZnY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapXnYnZ() {
+ return mapXnYnZ(this);
+ }
+ public Matrix4d mapXnYnZ(Matrix4d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapXnZY() {
+ return mapXnZY(this);
+ }
+ public Matrix4d mapXnZY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapXnZnY() {
+ return mapXnZnY(this);
+ }
+ public Matrix4d mapXnZnY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYXZ() {
+ return mapYXZ(this);
+ }
+ public Matrix4d mapYXZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYXnZ() {
+ return mapYXnZ(this);
+ }
+ public Matrix4d mapYXnZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYZX() {
+ return mapYZX(this);
+ }
+ public Matrix4d mapYZX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYZnX() {
+ return mapYZnX(this);
+ }
+ public Matrix4d mapYZnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYnXZ() {
+ return mapYnXZ(this);
+ }
+ public Matrix4d mapYnXZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYnXnZ() {
+ return mapYnXnZ(this);
+ }
+ public Matrix4d mapYnXnZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYnZX() {
+ return mapYnZX(this);
+ }
+ public Matrix4d mapYnZX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapYnZnX() {
+ return mapYnZnX(this);
+ }
+ public Matrix4d mapYnZnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZXY() {
+ return mapZXY(this);
+ }
+ public Matrix4d mapZXY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZXnY() {
+ return mapZXnY(this);
+ }
+ public Matrix4d mapZXnY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZYX() {
+ return mapZYX(this);
+ }
+ public Matrix4d mapZYX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZYnX() {
+ return mapZYnX(this);
+ }
+ public Matrix4d mapZYnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZnXY() {
+ return mapZnXY(this);
+ }
+ public Matrix4d mapZnXY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZnXnY() {
+ return mapZnXnY(this);
+ }
+ public Matrix4d mapZnXnY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZnYX() {
+ return mapZnYX(this);
+ }
+ public Matrix4d mapZnYX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapZnYnX() {
+ return mapZnYnX(this);
+ }
+ public Matrix4d mapZnYnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXYnZ() {
+ return mapnXYnZ(this);
+ }
+ public Matrix4d mapnXYnZ(Matrix4d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXZY() {
+ return mapnXZY(this);
+ }
+ public Matrix4d mapnXZY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXZnY() {
+ return mapnXZnY(this);
+ }
+ public Matrix4d mapnXZnY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXnYZ() {
+ return mapnXnYZ(this);
+ }
+ public Matrix4d mapnXnYZ(Matrix4d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXnYnZ() {
+ return mapnXnYnZ(this);
+ }
+ public Matrix4d mapnXnYnZ(Matrix4d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXnZY() {
+ return mapnXnZY(this);
+ }
+ public Matrix4d mapnXnZY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnXnZnY() {
+ return mapnXnZnY(this);
+ }
+ public Matrix4d mapnXnZnY(Matrix4d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYXZ() {
+ return mapnYXZ(this);
+ }
+ public Matrix4d mapnYXZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYXnZ() {
+ return mapnYXnZ(this);
+ }
+ public Matrix4d mapnYXnZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYZX() {
+ return mapnYZX(this);
+ }
+ public Matrix4d mapnYZX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYZnX() {
+ return mapnYZnX(this);
+ }
+ public Matrix4d mapnYZnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYnXZ() {
+ return mapnYnXZ(this);
+ }
+ public Matrix4d mapnYnXZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYnXnZ() {
+ return mapnYnXnZ(this);
+ }
+ public Matrix4d mapnYnXnZ(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYnZX() {
+ return mapnYnZX(this);
+ }
+ public Matrix4d mapnYnZX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnYnZnX() {
+ return mapnYnZnX(this);
+ }
+ public Matrix4d mapnYnZnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZXY() {
+ return mapnZXY(this);
+ }
+ public Matrix4d mapnZXY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZXnY() {
+ return mapnZXnY(this);
+ }
+ public Matrix4d mapnZXnY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZYX() {
+ return mapnZYX(this);
+ }
+ public Matrix4d mapnZYX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZYnX() {
+ return mapnZYnX(this);
+ }
+ public Matrix4d mapnZYnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZnXY() {
+ return mapnZnXY(this);
+ }
+ public Matrix4d mapnZnXY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZnXnY() {
+ return mapnZnXnY(this);
+ }
+ public Matrix4d mapnZnXnY(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZnYX() {
+ return mapnZnYX(this);
+ }
+ public Matrix4d mapnZnYX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d mapnZnYnX() {
+ return mapnZnYnX(this);
+ }
+ public Matrix4d mapnZnYnX(Matrix4d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d negateX() {
+ return _m00(-m00)._m01(-m01)._m02(-m02);
+ }
+ public Matrix4d negateX(Matrix4d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d negateY() {
+ return _m10(-m10)._m11(-m11)._m12(-m12);
+ }
+ public Matrix4d negateY(Matrix4d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4d negateZ() {
+ return _m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ public Matrix4d negateZ(Matrix4d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33);
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) && Math.isFinite(m03) &&
+ Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) && Math.isFinite(m13) &&
+ Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) && Math.isFinite(m23) &&
+ Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32) && Math.isFinite(m33);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4dStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4dStack.java
new file mode 100644
index 000000000..7b913198e
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4dStack.java
@@ -0,0 +1,185 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix4d} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix4dStack} class inherits from {@link Matrix4d}, so the current/top matrix is always the {@link Matrix4dStack}/{@link Matrix4d} itself. This
+ * affects all operations in {@link Matrix4d} that take another {@link Matrix4d} as parameter. If a {@link Matrix4dStack} is used as argument to those methods,
+ * the effective argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix4dStack extends Matrix4d {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix4dStack(int) constructor}.
+ */
+ private Matrix4d[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix4dStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix4dStack} simply only consists of this
+ * {@link Matrix4d}
+ */
+ public Matrix4dStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix4d[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix4d();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix4dStack} instance.
+ */
+ public Matrix4dStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix4dStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix4dStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix4dStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix4d and Matrix4dStack:
+ *
+ * - Matrix4d.equals(Matrix4dStack) is true iff all the 16 matrix elements are equal
+ * - Matrix4dStack.equals(Matrix4d) is true iff all the 16 matrix elements are equal
+ * - Matrix4dStack.equals(Matrix4dStack) is true iff all 16 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix4dStack) {
+ Matrix4dStack other = (Matrix4dStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix4dStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix4d m = new Matrix4d();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix4dStack cloned = (Matrix4dStack) super.clone();
+ Matrix4d[] clonedMats = new Matrix4d[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix4d) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4dc.java
new file mode 100644
index 000000000..567ca90d4
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4dc.java
@@ -0,0 +1,6289 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 4x4 matrix of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix4dc {
+
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation x=-1
when using the identity matrix.
+ */
+ int PLANE_NX = 0;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation x=1
when using the identity matrix.
+ */
+ int PLANE_PX = 1;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation y=-1
when using the identity matrix.
+ */
+ int PLANE_NY = 2;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation y=1
when using the identity matrix.
+ */
+ int PLANE_PY = 3;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation z=-1
when using the identity matrix.
+ */
+ int PLANE_NZ = 4;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation z=1
when using the identity matrix.
+ */
+ int PLANE_PZ = 5;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (-1, -1, -1)
when using the identity matrix.
+ */
+ int CORNER_NXNYNZ = 0;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (1, -1, -1)
when using the identity matrix.
+ */
+ int CORNER_PXNYNZ = 1;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (1, 1, -1)
when using the identity matrix.
+ */
+ int CORNER_PXPYNZ = 2;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (-1, 1, -1)
when using the identity matrix.
+ */
+ int CORNER_NXPYNZ = 3;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (1, -1, 1)
when using the identity matrix.
+ */
+ int CORNER_PXNYPZ = 4;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (-1, -1, 1)
when using the identity matrix.
+ */
+ int CORNER_NXNYPZ = 5;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (-1, 1, 1)
when using the identity matrix.
+ */
+ int CORNER_NXPYPZ = 6;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3d)}
+ * identifying the corner (1, 1, 1)
when using the identity matrix.
+ */
+ int CORNER_PXPYPZ = 7;
+
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents a perspective transformation.
+ */
+ byte PROPERTY_PERSPECTIVE = 1<<0;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents an affine transformation.
+ */
+ byte PROPERTY_AFFINE = 1<<1;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation.
+ */
+ byte PROPERTY_IDENTITY = 1<<2;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation.
+ */
+ byte PROPERTY_TRANSLATION = 1<<3;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the upper-left 3x3 submatrix represents an orthogonal
+ * matrix (i.e. orthonormal basis). For practical reasons, this property also always implies
+ * {@link #PROPERTY_AFFINE} in this implementation.
+ */
+ byte PROPERTY_ORTHONORMAL = 1<<4;
+
+ /**
+ * Return the assumed properties of this matrix. This is a bit-combination of
+ * {@link #PROPERTY_IDENTITY}, {@link #PROPERTY_AFFINE},
+ * {@link #PROPERTY_TRANSLATION} and {@link #PROPERTY_PERSPECTIVE}.
+ *
+ * @return the properties of the matrix
+ */
+ int properties();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m01();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m02();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ double m03();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m11();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m12();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ double m13();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m21();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m22();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ double m23();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m30();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m31();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m32();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ double m33();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mul(Matrix4dc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * This method neither assumes nor checks for any matrix properties of this
or right
+ * and will always perform a complete 4x4 matrix multiplication. This method should only be used whenever the
+ * multiplied matrices do not have any properties for which there are optimized multiplication methods available.
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mul0(Matrix4dc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the matrix with the supplied elements and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r03
+ * the m03 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r13
+ * the m13 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @param r23
+ * the m23 element of the right matrix
+ * @param r30
+ * the m30 element of the right matrix
+ * @param r31
+ * the m31 element of the right matrix
+ * @param r32
+ * the m32 element of the right matrix
+ * @param r33
+ * the m33 element of the right matrix
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mul(
+ double r00, double r01, double r02, double r03,
+ double r10, double r11, double r12, double r13,
+ double r20, double r21, double r22, double r23,
+ double r30, double r31, double r32, double r33, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the 3x3 matrix with the supplied elements expanded to a 4x4 matrix with
+ * all other matrix elements set to identity, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return this
+ */
+ Matrix4d mul3x3(
+ double r00, double r01, double r02,
+ double r10, double r11, double r12,
+ double r20, double r21, double r22, Matrix4d dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulLocal(Matrix4dc left, Matrix4d dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that this
matrix and the given left
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of left
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulLocalAffine(Matrix4dc left, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mul(Matrix3x2dc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mul(Matrix3x2fc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * The last row of the right
matrix is assumed to be (0, 0, 0, 1)
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mul(Matrix4x3dc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * The last row of the right
matrix is assumed to be (0, 0, 0, 1)
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mul(Matrix4x3fc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied parameter matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mul(Matrix4fc right, Matrix4d dest);
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied {@link #isAffine() affine} view
matrix and store the result in dest
.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the {@link #isAffine() affine} matrix to multiply this
symmetric perspective projection matrix by
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulPerspectiveAffine(Matrix4dc view, Matrix4d dest);
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied view
matrix and store the result in dest
.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix to multiply this
symmetric perspective projection matrix by
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulPerspectiveAffine(Matrix4x3dc view, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, which is assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that the given right
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulAffineR(Matrix4dc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that this
matrix and the given right
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulAffine(Matrix4dc right, Matrix4d dest);
+
+ /**
+ * Multiply this matrix, which is assumed to only contain a translation, by the supplied right
matrix, which is assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that this
matrix only contains a translation, and that the given right
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
).
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulTranslationAffine(Matrix4dc right, Matrix4d dest);
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied {@link #isAffine() affine} view
matrix
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the affine matrix which to multiply this
with
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d mulOrthoAffine(Matrix4dc view, Matrix4d dest);
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * by first multiplying each component of other
's 4x3 submatrix by otherFactor
,
+ * adding that to this
and storing the final result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * The matrices this
and other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's 4x3 components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d fma4x3(Matrix4dc other, double otherFactor, Matrix4d dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d add(Matrix4dc other, Matrix4d dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d sub(Matrix4dc subtrahend, Matrix4d dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mulComponentWise(Matrix4dc other, Matrix4d dest);
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d add4x3(Matrix4dc other, Matrix4d dest);
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d add4x3(Matrix4fc other, Matrix4d dest);
+
+ /**
+ * Component-wise subtract the upper 4x3 submatrices of subtrahend
from this
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d sub4x3(Matrix4dc subtrahend, Matrix4d dest);
+
+ /**
+ * Component-wise multiply the upper 4x3 submatrices of this
by other
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mul4x3ComponentWise(Matrix4dc other, Matrix4d dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * If this
matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing,
+ * and thus its last row is equal to (0, 0, 0, 1)
, then {@link #determinantAffine()} can be used instead of this method.
+ *
+ * @see #determinantAffine()
+ *
+ * @return the determinant
+ */
+ double determinant();
+
+ /**
+ * Return the determinant of the upper left 3x3 submatrix of this matrix.
+ *
+ * @return the determinant
+ */
+ double determinant3x3();
+
+ /**
+ * Return the determinant of this matrix by assuming that it represents an {@link #isAffine() affine} transformation and thus
+ * its last row is equal to (0, 0, 0, 1)
.
+ *
+ * @return the determinant
+ */
+ double determinantAffine();
+
+ /**
+ * Invert this
matrix and store the result in dest
.
+ *
+ * If this
matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing,
+ * and thus its last row is equal to (0, 0, 0, 1)
, then {@link #invertAffine(Matrix4d)} can be used instead of this method.
+ *
+ * @see #invertAffine(Matrix4d)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d invert(Matrix4d dest);
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(double, double, double, double, Matrix4d) perspective()} methods,
+ * that is, if this
is a symmetrical perspective frustum transformation,
+ * then this method builds the inverse of this
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix when being obtained via {@link #perspective(double, double, double, double, Matrix4d) perspective()}.
+ *
+ * @see #perspective(double, double, double, double, Matrix4d)
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4d invertPerspective(Matrix4d dest);
+
+ /**
+ * If this
is an arbitrary perspective projection matrix obtained via one of the {@link #frustum(double, double, double, double, double, double, Matrix4d) frustum()} methods,
+ * then this method builds the inverse of this
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix.
+ *
+ * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(double, double, double, double, Matrix4d) perspective()}, then
+ * {@link #invertPerspective(Matrix4d)} should be used instead.
+ *
+ * @see #frustum(double, double, double, double, double, double, Matrix4d)
+ * @see #invertPerspective(Matrix4d)
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4d invertFrustum(Matrix4d dest);
+
+ /**
+ * Invert this
orthographic projection matrix and store the result into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4d invertOrtho(Matrix4d dest);
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(double, double, double, double, Matrix4d) perspective()} methods,
+ * that is, if this
is a symmetrical perspective frustum transformation
+ * and the given view
matrix is {@link #isAffine() affine} and has unit scaling (for example by being obtained via {@link #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d) lookAt()}),
+ * then this method builds the inverse of this * view
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of the combination of the view and projection matrices, when both were obtained
+ * via the common methods {@link #perspective(double, double, double, double, Matrix4d) perspective()} and {@link #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d) lookAt()} or
+ * other methods, that build affine matrices, such as {@link #translate(double, double, double, Matrix4d) translate} and {@link #rotate(double, double, double, double, Matrix4d)}, except for {@link #scale(double, double, double, Matrix4d) scale()}.
+ *
+ * For the special cases of the matrices this
and view
mentioned above, this method is equivalent to the following code:
+ *
+ * dest.set(this).mul(view).invert();
+ *
+ *
+ * @param view
+ * the view transformation (must be {@link #isAffine() affine} and have unit scaling)
+ * @param dest
+ * will hold the inverse of this * view
+ * @return dest
+ */
+ Matrix4d invertPerspectiveView(Matrix4dc view, Matrix4d dest);
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(double, double, double, double, Matrix4d) perspective()} methods,
+ * that is, if this
is a symmetrical perspective frustum transformation
+ * and the given view
matrix has unit scaling,
+ * then this method builds the inverse of this * view
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of the combination of the view and projection matrices, when both were obtained
+ * via the common methods {@link #perspective(double, double, double, double, Matrix4d) perspective()} and {@link #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d) lookAt()} or
+ * other methods, that build affine matrices, such as {@link #translate(double, double, double, Matrix4d) translate} and {@link #rotate(double, double, double, double, Matrix4d)}, except for {@link #scale(double, double, double, Matrix4d) scale()}.
+ *
+ * For the special cases of the matrices this
and view
mentioned above, this method is equivalent to the following code:
+ *
+ * dest.set(this).mul(view).invert();
+ *
+ *
+ * @param view
+ * the view transformation (must have unit scaling)
+ * @param dest
+ * will hold the inverse of this * view
+ * @return dest
+ */
+ Matrix4d invertPerspectiveView(Matrix4x3dc view, Matrix4d dest);
+
+ /**
+ * Invert this matrix by assuming that it is an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and write the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d invertAffine(Matrix4d dest);
+
+ /**
+ * Transpose this
matrix and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d transpose(Matrix4d dest);
+
+ /**
+ * Transpose only the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * All other matrix elements are left unchanged.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d transpose3x3(Matrix4d dest);
+
+ /**
+ * Transpose only the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d transpose3x3(Matrix3d dest);
+
+ /**
+ * Get only the translation components (m30, m31, m32)
of this matrix and store them in the given vector xyz
.
+ *
+ * @param dest
+ * will hold the translation components of this matrix
+ * @return dest
+ */
+ Vector3d getTranslation(Vector3d dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
, y
and z
+ * @return dest
+ */
+ Vector3d getScale(Vector3d dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4d get(Matrix4d dest);
+
+ /**
+ * Get the current values of the upper 4x3 submatrix of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4x3d get4x3(Matrix4x3d dest);
+
+ /**
+ * Get the current values of the upper left 3x3 submatrix of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3d get3x3(Matrix3d dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaternionf#setFromUnnormalized(Matrix4dc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getUnnormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are normalized.
+ *
+ * @see Quaternionf#setFromNormalized(Matrix4dc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getNormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaterniond#setFromUnnormalized(Matrix4dc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getUnnormalizedRotation(Quaterniond dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are normalized.
+ *
+ * @see Quaterniond#setFromNormalized(Matrix4dc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getNormalizedRotation(Quaterniond dest);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given {@link DoubleBuffer}.
+ *
+ * @param index
+ * the absolute position into the {@link DoubleBuffer}
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given
+ * FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix4dc getToAddress(long address);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getFloats(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getFloats(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the elements of this matrix as float values in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getFloats(ByteBuffer buffer);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the elements of this matrix as float values in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getFloats(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get(double[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(double[], int)}.
+ *
+ * @see #get(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get(double[] arr);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied float array at the given offset.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied float array.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer getTransposed(DoubleBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer getTransposed(int index, DoubleBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get4x3Transposed(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x3Transposed(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get4x3Transposed(DoubleBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get4x3Transposed(int index, DoubleBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x3Transposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x3Transposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x3Transposed(ByteBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x3Transposed(int index, ByteBuffer buffer);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in that vector.
+ *
+ * @see Vector4d#mul(Matrix4dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4d transform(Vector4d v);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in dest
.
+ *
+ * @see Vector4d#mul(Matrix4dc, Vector4d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transform(Vector4dc v, Vector4d dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transform(double x, double y, double z, double w, Vector4d dest);
+
+ /**
+ * Transform/multiply the given vector by the transpose of this matrix and store the result in that vector.
+ *
+ * @see Vector4d#mulTranspose(Matrix4dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4d transformTranspose(Vector4d v);
+
+ /**
+ * Transform/multiply the given vector by the transpose of this matrix and store the result in dest
.
+ *
+ * @see Vector4d#mulTranspose(Matrix4dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transformTranspose(Vector4dc v, Vector4d dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by the transpose of this matrix
+ * and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transformTranspose(double x, double y, double z, double w, Vector4d dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in that vector.
+ *
+ * @see Vector4d#mulProject(Matrix4dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4d transformProject(Vector4d v);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * @see Vector4d#mulProject(Matrix4dc, Vector4d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transformProject(Vector4dc v, Vector4d dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide
+ * and store the x
, y
and z
components of the
+ * result in dest
.
+ *
+ * @see Vector3d#mulProject(Matrix4dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3d transformProject(Vector4dc v, Vector3d dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the direction to transform
+ * @param y
+ * the y coordinate of the direction to transform
+ * @param z
+ * the z coordinate of the direction to transform
+ * @param w
+ * the w coordinate of the direction to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transformProject(double x, double y, double z, double w, Vector4d dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in that vector.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @see Vector3d#mulProject(Matrix4dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3d transformProject(Vector3d v);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @see Vector3d#mulProject(Matrix4dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3d transformProject(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z)
by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3d transformProject(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by this matrix, perform perspective divide and store
+ * (x, y, z)
of the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the (x, y, z)
components of the result
+ * @return dest
+ */
+ Vector3d transformProject(double x, double y, double z, double w, Vector3d dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction. This method is therefore
+ * not suited for perspective projection transformations as it will not save the
+ * w
component of the transformed vector.
+ * For perspective projection use {@link #transform(Vector4d)} or
+ * {@link #transformProject(Vector3d)} when perspective divide should be applied, too.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector3dc, Vector3d)}.
+ *
+ * @see #transformPosition(Vector3dc, Vector3d)
+ * @see #transform(Vector4d)
+ * @see #transformProject(Vector3d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3d transformPosition(Vector3d v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction. This method is therefore
+ * not suited for perspective projection transformations as it will not save the
+ * w
component of the transformed vector.
+ * For perspective projection use {@link #transform(Vector4dc, Vector4d)} or
+ * {@link #transformProject(Vector3dc, Vector3d)} when perspective divide should be applied, too.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector3d)}.
+ *
+ * @see #transformPosition(Vector3d)
+ * @see #transform(Vector4dc, Vector4d)
+ * @see #transformProject(Vector3dc, Vector3d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPosition(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform/multiply the 3D-vector (x, y, z)
, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction. This method is therefore
+ * not suited for perspective projection transformations as it will not save the
+ * w
component of the transformed vector.
+ * For perspective projection use {@link #transform(double, double, double, double, Vector4d)} or
+ * {@link #transformProject(double, double, double, Vector3d)} when perspective divide should be applied, too.
+ *
+ * @see #transform(double, double, double, double, Vector4d)
+ * @see #transformProject(double, double, double, Vector3d)
+ *
+ * @param x
+ * the x coordinate of the position
+ * @param y
+ * the y coordinate of the position
+ * @param z
+ * the z coordinate of the position
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPosition(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector3dc, Vector3d)}.
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3d transformDirection(Vector3d v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector3d)}.
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformDirection(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector3fc, Vector3f)}.
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transformDirection(Vector3f v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector3f)}.
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformDirection(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform/multiply the 3D-vector (x, y, z)
, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * @param x
+ * the x coordinate of the direction to transform
+ * @param y
+ * the y coordinate of the direction to transform
+ * @param z
+ * the z coordinate of the direction to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformDirection(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform/multiply the 3D-vector (x, y, z)
, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * @param x
+ * the x coordinate of the direction to transform
+ * @param y
+ * the y coordinate of the direction to transform
+ * @param z
+ * the z coordinate of the direction to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformDirection(double x, double y, double z, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 4D-vector by assuming that this
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
).
+ *
+ * In order to store the result in another vector, use {@link #transformAffine(Vector4dc, Vector4d)}.
+ *
+ * @see #transformAffine(Vector4dc, Vector4d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4d transformAffine(Vector4d v);
+
+ /**
+ * Transform/multiply the given 4D-vector by assuming that this
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
) and store the result in dest
.
+ *
+ * In order to store the result in the same vector, use {@link #transformAffine(Vector4d)}.
+ *
+ * @see #transformAffine(Vector4d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformAffine(Vector4dc v, Vector4d dest);
+
+ /**
+ * Transform/multiply the 4D-vector (x, y, z, w)
by assuming that this
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
) and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the direction to transform
+ * @param y
+ * the y coordinate of the direction to transform
+ * @param z
+ * the z coordinate of the direction to transform
+ * @param w
+ * the w coordinate of the direction to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformAffine(double x, double y, double z, double w, Vector4d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scale(Vector3dc xyz, Matrix4d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scale(double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, double, Matrix4d)
+ *
+ * @param xyz
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scale(double xyz, Matrix4d dest);
+
+ /**
+ * Apply scaling to this matrix by by scaling the X axis by x
and the Y axis by y
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scaleXY(double x, double y, Matrix4d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4d scaleAround(double factor, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling all base axes by the given xyz
factor,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param xyz
+ * the factor to scale all three base axes by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scaleLocal(double xyz, Matrix4d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scaleLocal(double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using the given (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4d().translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz).mul(this, dest)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d scaleAroundLocal(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4d().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, dest)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4d scaleAroundLocal(double factor, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * @param ang
+ * the angle is in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(double ang, double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateTranslation(double ang, double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAffine(double ang, double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this {@link #isAffine() affine}
+ * matrix while using (ox, oy, oz)
as the rotation origin, and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is only applicable if this
is an {@link #isAffine() affine} matrix.
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAroundAffine(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix while using (ox, oy, oz)
as the rotation origin,
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAround(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateLocal(double ang, double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateLocalX(double ang, Matrix4d dest);
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateLocalY(double ang, Matrix4d dest);
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateLocalZ(double ang, Matrix4d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix while using (ox, oy, oz)
+ * as the rotation origin, and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * This method is equivalent to calling: translateLocal(-ox, -oy, -oz, dest).rotateLocal(quat).translateLocal(ox, oy, oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAroundLocal(Quaterniondc quat, double ox, double oy, double oz, Matrix4d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d translate(Vector3dc offset, Matrix4d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d translate(Vector3fc offset, Matrix4d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d translate(double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d translateLocal(Vector3fc offset, Matrix4d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d translateLocal(Vector3dc offset, Matrix4d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d translateLocal(double x, double y, double z, Matrix4d dest);
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateX(double ang, Matrix4d dest);
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateY(double ang, Matrix4d dest);
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateZ(double ang, Matrix4d dest);
+
+ /**
+ * Apply rotation about the Z axis to align the local +X
towards (dirX, dirY)
and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * The vector (dirX, dirY)
must be a unit vector.
+ *
+ * @param dirX
+ * the x component of the normalized direction
+ * @param dirY
+ * the y component of the normalized direction
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4d rotateTowardsXY(double dirX, double dirY, Matrix4d dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateXYZ(double angleX, double angleY, double angleZ, Matrix4d dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAffineXYZ(double angleX, double angleY, double angleZ, Matrix4d dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateZYX(double angleZ, double angleY, double angleX, Matrix4d dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAffineZYX(double angleZ, double angleY, double angleX, Matrix4d dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateYXZ(double angleY, double angleX, double angleZ, Matrix4d dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAffineYXZ(double angleY, double angleX, double angleZ, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(Quaterniondc quat, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(Quaternionfc quat, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this {@link #isAffine() affine} matrix and store
+ * the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAffine(Quaterniondc quat, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateTranslation(Quaterniondc quat, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateTranslation(Quaternionfc quat, Matrix4d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateLocal(Quaterniondc quat, Matrix4d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this {@link #isAffine() affine} matrix and store
+ * the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateAffine(Quaternionfc quat, Matrix4d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateLocal(Quaternionfc quat, Matrix4d dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(AxisAngle4f axisAngle, Matrix4d dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(AxisAngle4d axisAngle, Matrix4d dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4d)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(double angle, Vector3dc axis, Matrix4d dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4d)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotate(double angle, Vector3fc axis, Matrix4d dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..3]
+ */
+ Vector4d getRow(int row, Vector4d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the first three components of the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param dest
+ * will hold the first three row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..3]
+ */
+ Vector3d getRow(int row, Vector3d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ Vector4d getColumn(int column, Vector4d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the first three components of the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param dest
+ * will hold the first three column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ Vector3d getColumn(int column, Vector3d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the matrix element value at the given column and row.
+ *
+ * @param column
+ * the colum index in [0..3]
+ * @param row
+ * the row index in [0..3]
+ * @return the element value
+ */
+ double get(int column, int row);
+
+ /**
+ * Get the matrix element value at the given row and column.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param column
+ * the colum index in [0..3]
+ * @return the element value
+ */
+ double getRowColumn(int row, int column);
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into the upper left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d normal(Matrix4d dest);
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @see #get3x3(Matrix3d)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d normal(Matrix3d dest);
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d cofactor3x3(Matrix3d dest);
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d cofactor3x3(Matrix4d dest);
+
+ /**
+ * Normalize the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d normalize3x3(Matrix4d dest);
+
+ /**
+ * Normalize the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d normalize3x3(Matrix3d dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4d)} and then the method {@link #unprojectInv(double, double, double, int[], Vector4d) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(double, double, double, int[], Vector4d)
+ * @see #invert(Matrix4d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4d unproject(double winX, double winY, double winZ, int[] viewport, Vector4d dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4d)} and then the method {@link #unprojectInv(double, double, double, int[], Vector3d) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(double, double, double, int[], Vector3d)
+ * @see #invert(Matrix4d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3d unproject(double winX, double winY, double winZ, int[] viewport, Vector3d dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4d)} and then the method {@link #unprojectInv(double, double, double, int[], Vector4d) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(double, double, double, int[], Vector4d)
+ * @see #unproject(double, double, double, int[], Vector4d)
+ * @see #invert(Matrix4d)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4d unproject(Vector3dc winCoords, int[] viewport, Vector4d dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4d)} and then the method {@link #unprojectInv(double, double, double, int[], Vector4d) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(double, double, double, int[], Vector4d)
+ * @see #unproject(double, double, double, int[], Vector4d)
+ * @see #invert(Matrix4d)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3d unproject(Vector3dc winCoords, int[] viewport, Vector3d dest);
+
+ /**
+ * Unproject the given 2D window coordinates (winX, winY)
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4d)} and then the method {@link #unprojectInvRay(double, double, int[], Vector3d, Vector3d) unprojectInvRay()} can be invoked on it.
+ *
+ * @see #unprojectInvRay(double, double, int[], Vector3d, Vector3d)
+ * @see #invert(Matrix4d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4d unprojectRay(double winX, double winY, int[] viewport, Vector3d originDest, Vector3d dirDest);
+
+ /**
+ * Unproject the given 2D window coordinates winCoords
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4d)} and then the method {@link #unprojectInvRay(double, double, int[], Vector3d, Vector3d) unprojectInvRay()} can be invoked on it.
+ *
+ * @see #unprojectInvRay(double, double, int[], Vector3d, Vector3d)
+ * @see #unprojectRay(double, double, int[], Vector3d, Vector3d)
+ * @see #invert(Matrix4d)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4d unprojectRay(Vector2dc winCoords, int[] viewport, Vector3d originDest, Vector3d dirDest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(Vector3dc, int[], Vector4d) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by this
matrix.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(Vector3dc, int[], Vector4d)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4d unprojectInv(Vector3dc winCoords, int[] viewport, Vector4d dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(double, double, double, int[], Vector4d) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by this
matrix.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(double, double, double, int[], Vector4d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4d unprojectInv(double winX, double winY, double winZ, int[] viewport, Vector4d dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(Vector3dc, int[], Vector3d) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by this
matrix.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(Vector3dc, int[], Vector3d)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3d unprojectInv(Vector3dc winCoords, int[] viewport, Vector3d dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(double, double, double, int[], Vector3d) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by this
matrix.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(double, double, double, int[], Vector3d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3d unprojectInv(double winX, double winY, double winZ, int[] viewport, Vector3d dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method differs from {@link #unprojectRay(Vector2dc, int[], Vector3d, Vector3d) unprojectRay()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unprojectRay(Vector2dc, int[], Vector3d, Vector3d)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4d unprojectInvRay(Vector2dc winCoords, int[] viewport, Vector3d originDest, Vector3d dirDest);
+
+ /**
+ * Unproject the given 2D window coordinates (winX, winY)
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method differs from {@link #unprojectRay(double, double, int[], Vector3d, Vector3d) unprojectRay()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unprojectRay(double, double, int[], Vector3d, Vector3d)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4d unprojectInvRay(double winX, double winY, int[] viewport, Vector3d originDest, Vector3d dirDest);
+
+ /**
+ * Project the given (x, y, z)
position via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @param x
+ * the x-coordinate of the position to project
+ * @param y
+ * the y-coordinate of the position to project
+ * @param z
+ * the z-coordinate of the position to project
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector4d project(double x, double y, double z, int[] viewport, Vector4d winCoordsDest);
+
+ /**
+ * Project the given (x, y, z)
position via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @param x
+ * the x-coordinate of the position to project
+ * @param y
+ * the y-coordinate of the position to project
+ * @param z
+ * the z-coordinate of the position to project
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector3d project(double x, double y, double z, int[] viewport, Vector3d winCoordsDest);
+
+ /**
+ * Project the given position
via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #project(double, double, double, int[], Vector4d)
+ *
+ * @param position
+ * the position to project into window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector4d project(Vector3dc position, int[] viewport, Vector4d winCoordsDest);
+
+ /**
+ * Project the given position
via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #project(double, double, double, int[], Vector4d)
+ *
+ * @param position
+ * the position to project into window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector3d project(Vector3dc position, int[] viewport, Vector3d winCoordsDest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
and store the result in dest
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d reflect(double a, double b, double c, double d, Matrix4d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d reflect(double nx, double ny, double nz, double px, double py, double pz, Matrix4d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane, and store the result in dest
.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d reflect(Quaterniondc orientation, Vector3dc point, Matrix4d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d reflect(Vector3dc normal, Vector3dc point, Matrix4d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d ortho(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, boolean, Matrix4d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d orthoSymmetric(double width, double height, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, boolean, Matrix4d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d orthoSymmetricLH(double width, double height, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4d) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double, Matrix4d)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d ortho2D(double left, double right, double bottom, double top, Matrix4d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4d) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double, Matrix4d)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d ortho2DLH(double left, double right, double bottom, double top, Matrix4d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3dc, Vector3dc, Vector3dc, Matrix4d) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAlong(double, double, double, double, double, double, Matrix4d)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc, Matrix4d)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAlong(Vector3dc dir, Vector3dc up, Matrix4d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAt(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc, Matrix4d)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAt(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustum(double, double, double, double, double, double, Matrix4d) frustum()} or {@link #perspective(double, double, double, double, Matrix4d) perspective()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAtPerspective(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc, Matrix4d)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAtLH(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustumLH(double, double, double, double, double, double, Matrix4d) frustumLH()} or {@link #perspectiveLH(double, double, double, double, Matrix4d) perspectiveLH()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lookAtPerspectiveLH(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * This method is equivalent to calling: translate(w-1-2*x, h-1-2*y, 0, dest).scale(w, h, 1)
+ *
+ * If M
is this
matrix and T
the created transformation matrix,
+ * then the new matrix will be M * T
. So when transforming a
+ * vector v
with the new matrix by using M * T * v
, the
+ * created transformation will be applied first!
+ *
+ * @param x
+ * the tile's x coordinate/index (should be in [0..w)
)
+ * @param y
+ * the tile's y coordinate/index (should be in [0..h)
)
+ * @param w
+ * the number of tiles along the x axis
+ * @param h
+ * the number of tiles along the y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d tile(int x, int y, int w, int h, Matrix4d dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d perspective(double fovy, double aspect, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ Matrix4d perspectiveRect(double width, double height, double zNear, double zFar, boolean zZeroToOne);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ Matrix4d perspectiveRect(double width, double height, double zNear, double zFar);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar, boolean zZeroToOne);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @return this
+ */
+ Matrix4d perspectiveOffCenter(double fovy, double offAngleX, double offAngleY, double aspect, double zNear, double zFar);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d perspectiveLH(double fovy, double aspect, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d frustum(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4d dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Double#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Double#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d frustumLH(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4d dest);
+
+ /**
+ * Calculate a frustum plane of this
matrix, which
+ * can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given dest
.
+ *
+ * Generally, this method computes the frustum plane in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * The frustum plane will be given in the form of a general plane equation:
+ * a*x + b*y + c*z + d = 0
, where the given {@link Vector4d} components will
+ * hold the (a, b, c, d)
values of the equation.
+ *
+ * The plane normal, which is (a, b, c)
, is directed "inwards" of the frustum.
+ * Any plane/point test using a*x + b*y + c*z + d
therefore will yield a result greater than zero
+ * if the point is within the frustum (i.e. at the positive side of the frustum plane).
+ *
+ * For performing frustum culling, the class {@link FrustumIntersection} should be used instead of
+ * manually obtaining the frustum planes and testing them against points, spheres or axis-aligned boxes.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param plane
+ * one of the six possible planes, given as numeric constants
+ * {@link #PLANE_NX}, {@link #PLANE_PX},
+ * {@link #PLANE_NY}, {@link #PLANE_PY},
+ * {@link #PLANE_NZ} and {@link #PLANE_PZ}
+ * @param dest
+ * will hold the computed plane equation.
+ * The plane equation will be normalized, meaning that (a, b, c)
will be a unit vector
+ * @return dest
+ */
+ Vector4d frustumPlane(int plane, Vector4d dest);
+
+ /**
+ * Compute the corner coordinates of the frustum defined by this
matrix, which
+ * can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given point
.
+ *
+ * Generally, this method computes the frustum corners in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * Reference: http://geomalgorithms.com
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param corner
+ * one of the eight possible corners, given as numeric constants
+ * {@link #CORNER_NXNYNZ}, {@link #CORNER_PXNYNZ}, {@link #CORNER_PXPYNZ}, {@link #CORNER_NXPYNZ},
+ * {@link #CORNER_PXNYPZ}, {@link #CORNER_NXNYPZ}, {@link #CORNER_NXPYPZ}, {@link #CORNER_PXPYPZ}
+ * @param point
+ * will hold the resulting corner point coordinates
+ * @return point
+ */
+ Vector3d frustumCorner(int corner, Vector3d point);
+
+ /**
+ * Compute the eye/origin of the perspective frustum transformation defined by this
matrix,
+ * which can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given origin
.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(double, double, double, double, Matrix4d) perspective()}
+ * or {@link #frustum(double, double, double, double, double, double, Matrix4d) frustum()}.
+ *
+ * Generally, this method computes the origin in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * This method is equivalent to calling: invert(new Matrix4d()).transformProject(0, 0, -1, 0, origin)
+ * and in the case of an already available inverse of this
matrix, the method {@link #perspectiveInvOrigin(Vector3d)}
+ * on the inverse of the matrix should be used instead.
+ *
+ * Reference: http://geomalgorithms.com
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param origin
+ * will hold the origin of the coordinate system before applying this
+ * perspective projection transformation
+ * @return origin
+ */
+ Vector3d perspectiveOrigin(Vector3d origin);
+
+ /**
+ * Compute the eye/origin of the inverse of the perspective frustum transformation defined by this
matrix,
+ * which can be the inverse of a projection matrix or the inverse of a combined modelview-projection matrix, and store the result
+ * in the given dest
.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(double, double, double, double, Matrix4d) perspective()}
+ * or {@link #frustum(double, double, double, double, double, double, Matrix4d) frustum()}.
+ *
+ * If the inverse of the modelview-projection matrix is not available, then calling {@link #perspectiveOrigin(Vector3d)}
+ * on the original modelview-projection matrix is preferred.
+ *
+ * @see #perspectiveOrigin(Vector3d)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d perspectiveInvOrigin(Vector3d dest);
+
+ /**
+ * Return the vertical field-of-view angle in radians of this perspective transformation matrix.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(double, double, double, double, Matrix4d) perspective()}
+ * or {@link #frustum(double, double, double, double, double, double, Matrix4d) frustum()}.
+ *
+ * For orthogonal transformations this method will return 0.0
.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @return the vertical field-of-view angle in radians
+ */
+ double perspectiveFov();
+
+ /**
+ * Extract the near clip plane distance from this
perspective projection matrix.
+ *
+ * This method only works if this
is a perspective projection matrix, for example obtained via {@link #perspective(double, double, double, double, Matrix4d)}.
+ *
+ * @return the near clip plane distance
+ */
+ double perspectiveNear();
+
+ /**
+ * Extract the far clip plane distance from this
perspective projection matrix.
+ *
+ * This method only works if this
is a perspective projection matrix, for example obtained via {@link #perspective(double, double, double, double, Matrix4d)}.
+ *
+ * @return the far clip plane distance
+ */
+ double perspectiveFar();
+
+ /**
+ * Obtain the direction of a ray starting at the center of the coordinate system and going
+ * through the near frustum plane.
+ *
+ * This method computes the dir
vector in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * The parameters x
and y
are used to interpolate the generated ray direction
+ * from the bottom-left to the top-right frustum corners.
+ *
+ * For optimal efficiency when building many ray directions over the whole frustum,
+ * it is recommended to use this method only in order to compute the four corner rays at
+ * (0, 0)
, (1, 0)
, (0, 1)
and (1, 1)
+ * and then bilinearly interpolating between them; or to use the {@link FrustumRayBuilder}.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the interpolation factor along the left-to-right frustum planes, within [0..1]
+ * @param y
+ * the interpolation factor along the bottom-to-top frustum planes, within [0..1]
+ * @param dir
+ * will hold the normalized ray direction in the local frame of the coordinate system before
+ * transforming to homogeneous clipping space using this
matrix
+ * @return dir
+ */
+ Vector3d frustumRayDir(double x, double y, Vector3d dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4d inv = new Matrix4d(this).invert();
+ * inv.transformDirection(dir.set(0, 0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveZ(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d positiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4d inv = new Matrix4d(this).transpose();
+ * inv.transformDirection(dir.set(0, 0, 1));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d normalizedPositiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4d inv = new Matrix4d(this).invert();
+ * inv.transformDirection(dir.set(1, 0, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d positiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4d inv = new Matrix4d(this).transpose();
+ * inv.transformDirection(dir.set(1, 0, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d normalizedPositiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4d inv = new Matrix4d(this).invert();
+ * inv.transformDirection(dir.set(0, 1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d positiveY(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4d inv = new Matrix4d(this).transpose();
+ * inv.transformDirection(dir.set(0, 1, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d normalizedPositiveY(Vector3d dir);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
{@link #isAffine() affine} matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method only works with {@link #isAffine() affine} matrices.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invertAffine();
+ * inv.transformPosition(origin.set(0, 0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector3d originAffine(Vector3d origin);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view/projection transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invert();
+ * inv.transformPosition(origin.set(0, 0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector3d origin(Vector3d origin);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d shadow(Vector4dc light, double a, double b, double c, double d, Matrix4d dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, Matrix4d dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d shadow(Vector4dc light, Matrix4dc planeTransform, Matrix4d dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4dc planeTransform, Matrix4d dest);
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates, and store the result
+ * in dest
.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4d pick(double x, double y, double width, double height, int[] viewport, Matrix4d dest);
+
+ /**
+ * Determine whether this matrix describes an affine transformation. This is the case iff its last row is equal to (0, 0, 0, 1)
.
+ *
+ * @return true
iff this matrix is affine; false
otherwise
+ */
+ boolean isAffine();
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius, dest).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, Matrix4d dest);
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d arcball(double radius, Vector3dc center, double angleX, double angleY, Matrix4d dest);
+
+ /**
+ * Compute the range matrix for the Projected Grid transformation as described in chapter "2.4.2 Creating the range conversion matrix"
+ * of the paper Real-time water rendering - Introducing the projected grid concept
+ * based on the inverse of the view-projection matrix which is assumed to be this
, and store that range matrix into dest
.
+ *
+ * If the projected grid will not be visible then this method returns null
.
+ *
+ * This method uses the y = 0
plane for the projection.
+ *
+ * @param projector
+ * the projector view-projection transformation
+ * @param sLower
+ * the lower (smallest) Y-coordinate which any transformed vertex might have while still being visible on the projected grid
+ * @param sUpper
+ * the upper (highest) Y-coordinate which any transformed vertex might have while still being visible on the projected grid
+ * @param dest
+ * will hold the resulting range matrix
+ * @return the computed range matrix; or null
if the projected grid will not be visible
+ */
+ Matrix4d projectedGridRange(Matrix4dc projector, double sLower, double sUpper, Matrix4d dest);
+
+ /**
+ * Change the near and far clip plane distances of this
perspective frustum transformation matrix
+ * and store the result in dest
.
+ *
+ * This method only works if this
is a perspective projection frustum transformation, for example obtained
+ * via {@link #perspective(double, double, double, double, Matrix4d) perspective()} or {@link #frustum(double, double, double, double, double, double, Matrix4d) frustum()}.
+ *
+ * @see #perspective(double, double, double, double, Matrix4d)
+ * @see #frustum(double, double, double, double, double, double, Matrix4d)
+ *
+ * @param near
+ * the new near clip plane distance
+ * @param far
+ * the new far clip plane distance
+ * @param dest
+ * will hold the resulting matrix
+ * @return dest
+ */
+ Matrix4d perspectiveFrustumSlice(double near, double far, Matrix4d dest);
+
+ /**
+ * Build an ortographic projection transformation that fits the view-projection transformation represented by this
+ * into the given affine view
transformation.
+ *
+ * The transformation represented by this
must be given as the {@link #invert(Matrix4d) inverse} of a typical combined camera view-projection
+ * transformation, whose projection can be either orthographic or perspective.
+ *
+ * The view
must be an {@link #isAffine() affine} transformation which in the application of Cascaded Shadow Maps is usually the light view transformation.
+ * It be obtained via any affine transformation or for example via {@link #lookAt(double, double, double, double, double, double, double, double, double, Matrix4d) lookAt()}.
+ *
+ * Reference: OpenGL SDK - Cascaded Shadow Maps
+ *
+ * @param view
+ * the view transformation to build a corresponding orthographic projection to fit the frustum of this
+ * @param dest
+ * will hold the crop projection transformation
+ * @return dest
+ */
+ Matrix4d orthoCrop(Matrix4dc view, Matrix4d dest);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * by this
{@link #isAffine() affine} matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * Reference: http://dev.theomader.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector3d outMin, Vector3d outMax);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner min
and maximum corner max
+ * by this
{@link #isAffine() affine} matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4d transformAab(Vector3dc min, Vector3dc max, Vector3d outMin, Vector3d outMax);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d lerp(Matrix4dc other, double t, Matrix4d dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with direction
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invertAffine(), dest)
+ *
+ * @see #rotateTowards(double, double, double, double, double, double, Matrix4d)
+ *
+ * @param direction
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateTowards(Vector3dc direction, Vector3dc up, Matrix4d dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc, Matrix4d)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the upper left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the upper left of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order X * Y * Z
to obtain the identical matrix.
+ * This means that calling {@link Matrix4dc#rotateXYZ(double, double, double, Matrix4d)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4d m = ...; // <- matrix only representing rotation
+ * Matrix4d n = new Matrix4d();
+ * n.rotateXYZ(m.getEulerAnglesXYZ(new Vector3d()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3d getEulerAnglesXYZ(Vector3d dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the upper left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the upper left of this
only represents a rotation without scaling.
+ *
+ * Note that the returned Euler angles must be applied in the order Z * Y * X
to obtain the identical matrix.
+ * This means that calling {@link Matrix4dc#rotateZYX(double, double, double, Matrix4d)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4d m = ...; // <- matrix only representing rotation
+ * Matrix4d n = new Matrix4d();
+ * n.rotateZYX(m.getEulerAnglesZYX(new Vector3d()));
+ *
+ *
+ * Reference: http://nghiaho.com/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3d getEulerAnglesZYX(Vector3d dest);
+
+ /**
+ * Test whether the given point (x, y, z)
is within the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given point with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * When testing multiple points using the same transformation matrix, {@link FrustumIntersection} should be used instead.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the point
+ * @param y
+ * the y-coordinate of the point
+ * @param z
+ * the z-coordinate of the point
+ * @return true
if the given point is inside the frustum; false
otherwise
+ */
+ boolean testPoint(double x, double y, double z);
+
+ /**
+ * Test whether the given sphere is partly or completely within or outside of the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given sphere with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * When testing multiple spheres using the same transformation matrix, or more sophisticated/optimized intersection algorithms are required,
+ * {@link FrustumIntersection} should be used instead.
+ *
+ * The algorithm implemented by this method is conservative. This means that in certain circumstances a false positive
+ * can occur, when the method returns true
for spheres that are actually not visible.
+ * See iquilezles.org for an examination of this problem.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the sphere's center
+ * @param y
+ * the y-coordinate of the sphere's center
+ * @param z
+ * the z-coordinate of the sphere's center
+ * @param r
+ * the sphere's radius
+ * @return true
if the given sphere is partly or completely inside the frustum; false
otherwise
+ */
+ boolean testSphere(double x, double y, double z, double r);
+
+ /**
+ * Test whether the given axis-aligned box is partly or completely within or outside of the frustum defined by this
matrix.
+ * The box is specified via its min and max corner coordinates.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given axis-aligned box with its minimum corner coordinates (minX, minY, minZ)
+ * and maximum corner coordinates (maxX, maxY, maxZ)
given in space M
is within the clip space.
+ *
+ * When testing multiple axis-aligned boxes using the same transformation matrix, or more sophisticated/optimized intersection algorithms are required,
+ * {@link FrustumIntersection} should be used instead.
+ *
+ * The algorithm implemented by this method is conservative. This means that in certain circumstances a false positive
+ * can occur, when the method returns -1
for boxes that are actually not visible/do not intersect the frustum.
+ * See iquilezles.org for an examination of this problem.
+ *
+ * Reference: Efficient View Frustum Culling
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param minX
+ * the x-coordinate of the minimum corner
+ * @param minY
+ * the y-coordinate of the minimum corner
+ * @param minZ
+ * the z-coordinate of the minimum corner
+ * @param maxX
+ * the x-coordinate of the maximum corner
+ * @param maxY
+ * the y-coordinate of the maximum corner
+ * @param maxZ
+ * the z-coordinate of the maximum corner
+ * @return true
if the axis-aligned box is completely or partly inside of the frustum; false
otherwise
+ */
+ boolean testAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ);
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d obliqueZ(double a, double b, Matrix4d dest);
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3d)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3d)}) and the
+ * given vector up
, and store the result in dest
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from calling
+ * {@link Matrix4d#setLookAt(Vector3dc, Vector3dc, Vector3dc)} with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3d)}), the sum of this position and the
+ * negated local Z axis as well as the given vector up
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4d withLookAtUp(Vector3dc up, Matrix4d dest);
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3d)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3d)}) and the
+ * given vector (upX, upY, upZ)
, and store the result in dest
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from calling
+ * {@link Matrix4d#setLookAt(double, double, double, double, double, double, double, double, double)} called with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3d)}), the sum of this position and the
+ * negated local Z axis as well as the given vector (upX, upY, upZ)
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param upX
+ * the x coordinate of the up vector
+ * @param upY
+ * the y coordinate of the up vector
+ * @param upZ
+ * the z coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4d withLookAtUp(double upX, double upY, double upZ, Matrix4d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapXZY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapXZnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapXnYnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapXnZY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapXnZnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYXZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYXnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYZX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYZnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYnXZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYnXnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYnZX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapYnZnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZXY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZXnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZYX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZYnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZnXY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZnXnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZnYX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapZnYnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXYnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXZY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXZnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXnYZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXnYnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXnZY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnXnZnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYXZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYXnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYZX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYZnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYnXZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYnXnZ(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYnZX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnYnZnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZXY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZXnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZYX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZYnX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZnXY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZnXnY(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZnYX(Matrix4d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d mapnZnYnX(Matrix4d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d negateX(Matrix4d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d negateY(Matrix4d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4d negateZ(Matrix4d dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix4dc m, double delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4f.java
new file mode 100644
index 000000000..85e92cceb
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4f.java
@@ -0,0 +1,15355 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+
+/**
+ * Contains the definition of a 4x4 matrix of floats, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20 m30
+ * m01 m11 m21 m31
+ * m02 m12 m22 m32
+ * m03 m13 m23 m33
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Matrix4f implements Externalizable, Cloneable, Matrix4fc {
+
+ private static final long serialVersionUID = 1L;
+
+ float m00, m01, m02, m03;
+ float m10, m11, m12, m13;
+ float m20, m21, m22, m23;
+ float m30, m31, m32, m33;
+
+ int properties;
+
+ /**
+ * Create a new {@link Matrix4f} and set it to {@link #identity() identity}.
+ */
+ public Matrix4f() {
+ this._m00(1.0f)
+ ._m11(1.0f)
+ ._m22(1.0f)
+ ._m33(1.0f)
+ ._properties(PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Create a new {@link Matrix4f} by setting its uppper left 3x3 submatrix to the values of the given {@link Matrix3fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix3fc}
+ */
+ public Matrix4f(Matrix3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4f} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix4fc} to copy the values from
+ */
+ public Matrix4f(Matrix4fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4f} and set its upper 4x3 submatrix to the given matrix mat
+ * and all other elements to identity.
+ *
+ * @param mat
+ * the {@link Matrix4x3fc} to copy the values from
+ */
+ public Matrix4f(Matrix4x3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4f} and make it a copy of the given matrix.
+ *
+ * Note that due to the given {@link Matrix4dc} storing values in double-precision and the constructed {@link Matrix4f} storing them
+ * in single-precision, there is the possibility of losing precision.
+ *
+ * @param mat
+ * the {@link Matrix4dc} to copy the values from
+ */
+ public Matrix4f(Matrix4dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new 4x4 matrix using the supplied float values.
+ *
+ * The matrix layout will be:
+ * m00, m10, m20, m30
+ * m01, m11, m21, m31
+ * m02, m12, m22, m32
+ * m03, m13, m23, m33
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m02
+ * the value of m02
+ * @param m03
+ * the value of m03
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m12
+ * the value of m12
+ * @param m13
+ * the value of m13
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ * @param m22
+ * the value of m22
+ * @param m23
+ * the value of m23
+ * @param m30
+ * the value of m30
+ * @param m31
+ * the value of m31
+ * @param m32
+ * the value of m32
+ * @param m33
+ * the value of m33
+ */
+ public Matrix4f(float m00, float m01, float m02, float m03,
+ float m10, float m11, float m12, float m13,
+ float m20, float m21, float m22, float m23,
+ float m30, float m31, float m32, float m33) {
+ this._m00(m00)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(m11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ .determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4f} by reading its 16 float components from the given {@link FloatBuffer}
+ * at the buffer's current position.
+ *
+ * That FloatBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link FloatBuffer} to read the matrix values from
+ */
+ public Matrix4f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4f} and initialize its four columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ */
+ public Matrix4f(Vector4fc col0, Vector4fc col1, Vector4fc col2, Vector4fc col3) {
+ set(col0, col1, col2, col3);
+ }
+
+ Matrix4f _properties(int properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ /**
+ * Assume the given properties about this matrix.
+ *
+ * Use one or multiple of 0, {@link Matrix4fc#PROPERTY_IDENTITY},
+ * {@link Matrix4fc#PROPERTY_TRANSLATION}, {@link Matrix4fc#PROPERTY_AFFINE},
+ * {@link Matrix4fc#PROPERTY_PERSPECTIVE}, {@link Matrix4fc#PROPERTY_ORTHONORMAL}.
+ *
+ * @param properties
+ * bitset of the properties to assume about this matrix
+ * @return this
+ */
+ public Matrix4f assume(int properties) {
+ this._properties(properties);
+ return this;
+ }
+
+ /**
+ * Compute and set the matrix properties returned by {@link #properties()} based
+ * on the current matrix element values.
+ *
+ * @return this
+ */
+ public Matrix4f determineProperties() {
+ int properties = 0;
+ if (m03 == 0.0f && m13 == 0.0f) {
+ if (m23 == 0.0f && m33 == 1.0f) {
+ properties |= PROPERTY_AFFINE;
+ if (m00 == 1.0f && m01 == 0.0f && m02 == 0.0f && m10 == 0.0f && m11 == 1.0f && m12 == 0.0f
+ && m20 == 0.0f && m21 == 0.0f && m22 == 1.0f) {
+ properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ if (m30 == 0.0f && m31 == 0.0f && m32 == 0.0f)
+ properties |= PROPERTY_IDENTITY;
+ }
+ /*
+ * We do not determine orthogonality, since it would require arbitrary epsilons
+ * and is rather expensive (6 dot products) in the worst case.
+ */
+ } else if (m01 == 0.0f && m02 == 0.0f && m10 == 0.0f && m12 == 0.0f && m20 == 0.0f && m21 == 0.0f
+ && m30 == 0.0f && m31 == 0.0f && m33 == 0.0f) {
+ properties |= PROPERTY_PERSPECTIVE;
+ }
+ }
+ this.properties = properties;
+ return this;
+ }
+
+ public int properties() {
+ return properties;
+ }
+
+ public float m00() {
+ return m00;
+ }
+ public float m01() {
+ return m01;
+ }
+ public float m02() {
+ return m02;
+ }
+ public float m03() {
+ return m03;
+ }
+ public float m10() {
+ return m10;
+ }
+ public float m11() {
+ return m11;
+ }
+ public float m12() {
+ return m12;
+ }
+ public float m13() {
+ return m13;
+ }
+ public float m20() {
+ return m20;
+ }
+ public float m21() {
+ return m21;
+ }
+ public float m22() {
+ return m22;
+ }
+ public float m23() {
+ return m23;
+ }
+ public float m30() {
+ return m30;
+ }
+ public float m31() {
+ return m31;
+ }
+ public float m32() {
+ return m32;
+ }
+ public float m33() {
+ return m33;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix4f m00(float m00) {
+ this.m00 = m00;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m00 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix4f m01(float m01) {
+ this.m01 = m01;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m01 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ public Matrix4f m02(float m02) {
+ this.m02 = m02;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m02 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 3.
+ *
+ * @param m03
+ * the new value
+ * @return this
+ */
+ public Matrix4f m03(float m03) {
+ this.m03 = m03;
+ if (m03 != 0.0f)
+ properties = 0;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix4f m10(float m10) {
+ this.m10 = m10;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m10 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix4f m11(float m11) {
+ this.m11 = m11;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m11 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ public Matrix4f m12(float m12) {
+ this.m12 = m12;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m12 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 3.
+ *
+ * @param m13
+ * the new value
+ * @return this
+ */
+ public Matrix4f m13(float m13) {
+ this.m13 = m13;
+ if (m13 != 0.0f)
+ properties = 0;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ public Matrix4f m20(float m20) {
+ this.m20 = m20;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m20 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ public Matrix4f m21(float m21) {
+ this.m21 = m21;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m21 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ public Matrix4f m22(float m22) {
+ this.m22 = m22;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m22 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 3.
+ *
+ * @param m23
+ * the new value
+ * @return this
+ */
+ public Matrix4f m23(float m23) {
+ this.m23 = m23;
+ if (m23 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ public Matrix4f m30(float m30) {
+ this.m30 = m30;
+ if (m30 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ public Matrix4f m31(float m31) {
+ this.m31 = m31;
+ if (m31 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ public Matrix4f m32(float m32) {
+ this.m32 = m32;
+ if (m32 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 3.
+ *
+ * @param m33
+ * the new value
+ * @return this
+ */
+ public Matrix4f m33(float m33) {
+ this.m33 = m33;
+ if (m33 != 0.0f)
+ properties &= ~(PROPERTY_PERSPECTIVE);
+ if (m33 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL | PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix4f _m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix4f _m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ Matrix4f _m02(float m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 3 without updating the properties of the matrix.
+ *
+ * @param m03
+ * the new value
+ * @return this
+ */
+ Matrix4f _m03(float m03) {
+ this.m03 = m03;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix4f _m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix4f _m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ Matrix4f _m12(float m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 3 without updating the properties of the matrix.
+ *
+ * @param m13
+ * the new value
+ * @return this
+ */
+ Matrix4f _m13(float m13) {
+ this.m13 = m13;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix4f _m20(float m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix4f _m21(float m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ Matrix4f _m22(float m22) {
+ this.m22 = m22;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 3 without updating the properties of the matrix.
+ *
+ * @param m23
+ * the new value
+ * @return this
+ */
+ Matrix4f _m23(float m23) {
+ this.m23 = m23;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ Matrix4f _m30(float m30) {
+ this.m30 = m30;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ Matrix4f _m31(float m31) {
+ this.m31 = m31;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ Matrix4f _m32(float m32) {
+ this.m32 = m32;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 3 and row 3 without updating the properties of the matrix.
+ *
+ * @param m33
+ * the new value
+ * @return this
+ */
+ Matrix4f _m33(float m33) {
+ this.m33 = m33;
+ return this;
+ }
+
+ /**
+ * Reset this matrix to the identity.
+ *
+ * Please note that if a call to {@link #identity()} is immediately followed by a call to:
+ * {@link #translate(float, float, float) translate},
+ * {@link #rotate(float, float, float, float) rotate},
+ * {@link #scale(float, float, float) scale},
+ * {@link #perspective(float, float, float, float) perspective},
+ * {@link #frustum(float, float, float, float, float, float) frustum},
+ * {@link #ortho(float, float, float, float, float, float) ortho},
+ * {@link #ortho2D(float, float, float, float) ortho2D},
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt},
+ * {@link #lookAlong(float, float, float, float, float, float) lookAlong},
+ * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with:
+ * {@link #translation(float, float, float) translation},
+ * {@link #rotation(float, float, float, float) rotation},
+ * {@link #scaling(float, float, float) scaling},
+ * {@link #setPerspective(float, float, float, float) setPerspective},
+ * {@link #setFrustum(float, float, float, float, float, float) setFrustum},
+ * {@link #setOrtho(float, float, float, float, float, float) setOrtho},
+ * {@link #setOrtho2D(float, float, float, float) setOrtho2D},
+ * {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt},
+ * {@link #setLookAlong(float, float, float, float, float, float) setLookAlong},
+ * or any of their overloads.
+ *
+ * @return this
+ */
+ public Matrix4f identity() {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return this;
+ return
+ _m00(1.0f).
+ _m01(0.0f).
+ _m02(0.0f).
+ _m03(0.0f).
+ _m10(0.0f).
+ _m11(1.0f).
+ _m12(0.0f).
+ _m13(0.0f).
+ _m20(0.0f).
+ _m21(0.0f).
+ _m22(1.0f).
+ _m23(0.0f).
+ _m30(0.0f).
+ _m31(0.0f).
+ _m32(0.0f).
+ _m33(1.0f).
+ _properties(PROPERTY_IDENTITY | PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * @see #Matrix4f(Matrix4fc)
+ * @see #get(Matrix4f)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4f set(Matrix4fc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m03(m.m03()).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m13(m.m13()).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22()).
+ _m23(m.m23()).
+ _m30(m.m30()).
+ _m31(m.m31()).
+ _m32(m.m32()).
+ _m33(m.m33()).
+ _properties(m.properties());
+ }
+
+ /**
+ * Store the values of the transpose of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the transposed values from
+ * @return this
+ */
+ public Matrix4f setTransposed(Matrix4fc m) {
+ if ((m.properties() & PROPERTY_IDENTITY) != 0)
+ return this.identity();
+ return setTransposedInternal(m);
+ }
+ private Matrix4f setTransposedInternal(Matrix4fc m) {
+ float nm10 = m.m01(), nm12 = m.m21(), nm13 = m.m31();
+ float nm20 = m.m02(), nm21 = m.m12(), nm30 = m.m03();
+ float nm31 = m.m13(), nm32 = m.m23();
+ return this
+ ._m00(m.m00())._m01(m.m10())._m02(m.m20())._m03(m.m30())
+ ._m10(nm10)._m11(m.m11())._m12(nm12)._m13(nm13)
+ ._m20(nm20)._m21(nm21)._m22(m.m22())._m23(m.m32())
+ ._m30(nm30)._m31(nm31)._m32(nm32)._m33(m.m33())
+ ._properties(m.properties() & PROPERTY_IDENTITY);
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix
+ * and set the other matrix elements to identity.
+ *
+ * @see #Matrix4f(Matrix4x3fc)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4f set(Matrix4x3fc m) {
+ return
+ _m00(m.m00()).
+ _m01(m.m01()).
+ _m02(m.m02()).
+ _m03(0.0f).
+ _m10(m.m10()).
+ _m11(m.m11()).
+ _m12(m.m12()).
+ _m13(0.0f).
+ _m20(m.m20()).
+ _m21(m.m21()).
+ _m22(m.m22()).
+ _m23(0.0f).
+ _m30(m.m30()).
+ _m31(m.m31()).
+ _m32(m.m32()).
+ _m33(1.0f).
+ _properties(m.properties() | PROPERTY_AFFINE);
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * Note that due to the given matrix m
storing values in double-precision and this
matrix storing
+ * them in single-precision, there is the possibility to lose precision.
+ *
+ * @see #Matrix4f(Matrix4dc)
+ * @see #get(Matrix4d)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4f set(Matrix4dc m) {
+ return this
+ ._m00((float) m.m00())
+ ._m01((float) m.m01())
+ ._m02((float) m.m02())
+ ._m03((float) m.m03())
+ ._m10((float) m.m10())
+ ._m11((float) m.m11())
+ ._m12((float) m.m12())
+ ._m13((float) m.m13())
+ ._m20((float) m.m20())
+ ._m21((float) m.m21())
+ ._m22((float) m.m22())
+ ._m23((float) m.m23())
+ ._m30((float) m.m30())
+ ._m31((float) m.m31())
+ ._m32((float) m.m32())
+ ._m33((float) m.m33())
+ ._properties(m.properties());
+ }
+
+ /**
+ * Set the upper left 3x3 submatrix of this {@link Matrix4f} to the given {@link Matrix3fc}
+ * and the rest to identity.
+ *
+ * @see #Matrix4f(Matrix3fc)
+ *
+ * @param mat
+ * the {@link Matrix3fc}
+ * @return this
+ */
+ public Matrix4f set(Matrix3fc mat) {
+ return this
+ ._m00(mat.m00())
+ ._m01(mat.m01())
+ ._m02(mat.m02())
+ ._m03(0.0f)
+ ._m10(mat.m10())
+ ._m11(mat.m11())
+ ._m12(mat.m12())
+ ._m13(0.0f)
+ ._m20(mat.m20())
+ ._m21(mat.m21())
+ ._m22(mat.m22())
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f).
+ _properties(PROPERTY_AFFINE);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Matrix4f set(AxisAngle4f axisAngle) {
+ float x = axisAngle.x;
+ float y = axisAngle.y;
+ float z = axisAngle.z;
+ float angle = axisAngle.angle;
+ double n = Math.sqrt(x*x + y*y + z*z);
+ n = 1/n;
+ x *= n;
+ y *= n;
+ z *= n;
+ float s = Math.sin(angle);
+ float c = Math.cosFromSin(s, angle);
+ float omc = 1.0f - c;
+ this._m00((float)(c + x*x*omc))
+ ._m11((float)(c + y*y*omc))
+ ._m22((float)(c + z*z*omc));
+ float tmp1 = x*y*omc;
+ float tmp2 = z*s;
+ this._m10((float)(tmp1 - tmp2))
+ ._m01((float)(tmp1 + tmp2));
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ this._m20((float)(tmp1 + tmp2))
+ ._m02((float)(tmp1 - tmp2));
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ return this
+ ._m21((float)(tmp1 - tmp2))
+ ._m12((float)(tmp1 + tmp2))
+ ._m03(0.0f)
+ ._m13(0.0f)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Matrix4f set(AxisAngle4d axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double n = Math.sqrt(x*x + y*y + z*z);
+ n = 1/n;
+ x *= n;
+ y *= n;
+ z *= n;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ this._m00((float)(c + x*x*omc))
+ ._m11((float)(c + y*y*omc))
+ ._m22((float)(c + z*z*omc));
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ this._m10((float)(tmp1 - tmp2))
+ ._m01((float)(tmp1 + tmp2));
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ this._m20((float)(tmp1 + tmp2))
+ ._m02((float)(tmp1 - tmp2));
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ return this
+ ._m21((float)(tmp1 - tmp2))
+ ._m12((float)(tmp1 + tmp2))
+ ._m03(0.0f)
+ ._m13(0.0f)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link Quaternionfc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param q
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4f set(Quaternionfc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link Quaterniondc}.
+ *
+ * Reference: http://www.euclideanspace.com/
+ *
+ * @param q
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4f set(Quaterniondc q) {
+ double w2 = q.w() * q.w();
+ double x2 = q.x() * q.x();
+ double y2 = q.y() * q.y();
+ double z2 = q.z() * q.z();
+ double zw = q.z() * q.w();
+ double xy = q.x() * q.y();
+ double xz = q.x() * q.z();
+ double yw = q.y() * q.w();
+ double yz = q.y() * q.z();
+ double xw = q.x() * q.w();
+ return
+ _m00((float) (w2 + x2 - z2 - y2)).
+ _m01((float) (xy + zw + zw + xy)).
+ _m02((float) (xz - yw + xz - yw)).
+ _m03(0.0f).
+ _m10((float) (-zw + xy - zw + xy)).
+ _m11((float) (y2 - z2 + w2 - x2)).
+ _m12((float) (yz + yz + xw + xw)).
+ _m13(0.0f).
+ _m20((float) (yw + xz + xz + yw)).
+ _m21((float) (yz + yz - xw - xw)).
+ _m22((float) (z2 - y2 - x2 + w2)).
+ _m30(0.0f).
+ _m31(0.0f).
+ _m32(0.0f).
+ _m33(1.0f).
+ _properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set the upper left 3x3 submatrix of this {@link Matrix4f} to that of the given {@link Matrix4f}
+ * and don't change the other elements.
+ *
+ * @param mat
+ * the {@link Matrix4f}
+ * @return this
+ */
+ public Matrix4f set3x3(Matrix4f mat) {
+ MemUtil.INSTANCE.copy3x3(mat, this);
+ return _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE));
+ }
+
+
+ /**
+ * Set the upper 4x3 submatrix of this {@link Matrix4f} to the given {@link Matrix4x3fc}
+ * and don't change the other elements.
+ *
+ * @see Matrix4x3f#get(Matrix4f)
+ *
+ * @param mat
+ * the {@link Matrix4x3fc}
+ * @return this
+ */
+ public Matrix4f set4x3(Matrix4x3fc mat) {
+ return
+ _m00(mat.m00()).
+ _m01(mat.m01()).
+ _m02(mat.m02()).
+ _m10(mat.m10()).
+ _m11(mat.m11()).
+ _m12(mat.m12()).
+ _m20(mat.m20()).
+ _m21(mat.m21()).
+ _m22(mat.m22()).
+ _m30(mat.m30()).
+ _m31(mat.m31()).
+ _m32(mat.m32()).
+ _properties(properties & mat.properties() & ~(PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Set the upper 4x3 submatrix of this {@link Matrix4f} to the upper 4x3 submatrix of the given {@link Matrix4f}
+ * and don't change the other elements.
+ *
+ * @param mat
+ * the {@link Matrix4f}
+ * @return this
+ */
+ public Matrix4f set4x3(Matrix4f mat) {
+ MemUtil.INSTANCE.copy4x3(mat, this);
+ return _properties(properties & mat.properties & ~(PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4f mul(Matrix4fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4f mul(Matrix4fc right, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0 && (right.properties() & PROPERTY_AFFINE) != 0)
+ return mulTranslationAffine(right, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0 && (right.properties() & PROPERTY_AFFINE) != 0)
+ return mulAffine(right, dest);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0 && (right.properties() & PROPERTY_AFFINE) != 0)
+ return mulPerspectiveAffine(right, dest);
+ else if ((right.properties() & PROPERTY_AFFINE) != 0)
+ return mulAffineR(right, dest);
+ return mul0(right, dest);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * This method neither assumes nor checks for any matrix properties of this
or right
+ * and will always perform a complete 4x4 matrix multiplication. This method should only be used whenever the
+ * multiplied matrices do not have any properties for which there are optimized multiplication methods available.
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4f mul0(Matrix4fc right) {
+ return mul0(right, this);
+ }
+
+ public Matrix4f mul0(Matrix4fc right, Matrix4f dest) {
+ float nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), Math.fma(m20, right.m02(), m30 * right.m03())));
+ float nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), Math.fma(m21, right.m02(), m31 * right.m03())));
+ float nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), Math.fma(m22, right.m02(), m32 * right.m03())));
+ float nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), Math.fma(m23, right.m02(), m33 * right.m03())));
+ float nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), Math.fma(m20, right.m12(), m30 * right.m13())));
+ float nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), Math.fma(m21, right.m12(), m31 * right.m13())));
+ float nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), Math.fma(m22, right.m12(), m32 * right.m13())));
+ float nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), Math.fma(m23, right.m12(), m33 * right.m13())));
+ float nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), Math.fma(m20, right.m22(), m30 * right.m23())));
+ float nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), Math.fma(m21, right.m22(), m31 * right.m23())));
+ float nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), Math.fma(m22, right.m22(), m32 * right.m23())));
+ float nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), Math.fma(m23, right.m22(), m33 * right.m23())));
+ float nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30 * right.m33())));
+ float nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31 * right.m33())));
+ float nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32 * right.m33())));
+ float nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33 * right.m33())));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Multiply this matrix by the matrix with the supplied elements.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r03
+ * the m03 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r13
+ * the m13 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @param r23
+ * the m23 element of the right matrix
+ * @param r30
+ * the m30 element of the right matrix
+ * @param r31
+ * the m31 element of the right matrix
+ * @param r32
+ * the m32 element of the right matrix
+ * @param r33
+ * the m33 element of the right matrix
+ * @return this
+ */
+ public Matrix4f mul(
+ float r00, float r01, float r02, float r03,
+ float r10, float r11, float r12, float r13,
+ float r20, float r21, float r22, float r23,
+ float r30, float r31, float r32, float r33) {
+ return mul(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, this);
+ }
+
+ public Matrix4f mul(
+ float r00, float r01, float r02, float r03,
+ float r10, float r11, float r12, float r13,
+ float r20, float r21, float r22, float r23,
+ float r30, float r31, float r32, float r33, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return mulAffineL(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest);
+ return mulGeneric(r00, r01, r02, r03, r10, r11, r12, r13, r20, r21, r22, r23, r30, r31, r32, r33, dest);
+ }
+ private Matrix4f mulAffineL(
+ float r00, float r01, float r02, float r03,
+ float r10, float r11, float r12, float r13,
+ float r20, float r21, float r22, float r23,
+ float r30, float r31, float r32, float r33, Matrix4f dest) {
+ float nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03)));
+ float nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03)));
+ float nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03)));
+ float nm03 = r03;
+ float nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13)));
+ float nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13)));
+ float nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13)));
+ float nm13 = r13;
+ float nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23)));
+ float nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23)));
+ float nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23)));
+ float nm23 = r23;
+ float nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33)));
+ float nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33)));
+ float nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33)));
+ float nm33 = r33;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(PROPERTY_AFFINE);
+ }
+ private Matrix4f mulGeneric(
+ float r00, float r01, float r02, float r03,
+ float r10, float r11, float r12, float r13,
+ float r20, float r21, float r22, float r23,
+ float r30, float r31, float r32, float r33, Matrix4f dest) {
+ float nm00 = Math.fma(m00, r00, Math.fma(m10, r01, Math.fma(m20, r02, m30 * r03)));
+ float nm01 = Math.fma(m01, r00, Math.fma(m11, r01, Math.fma(m21, r02, m31 * r03)));
+ float nm02 = Math.fma(m02, r00, Math.fma(m12, r01, Math.fma(m22, r02, m32 * r03)));
+ float nm03 = Math.fma(m03, r00, Math.fma(m13, r01, Math.fma(m23, r02, m33 * r03)));
+ float nm10 = Math.fma(m00, r10, Math.fma(m10, r11, Math.fma(m20, r12, m30 * r13)));
+ float nm11 = Math.fma(m01, r10, Math.fma(m11, r11, Math.fma(m21, r12, m31 * r13)));
+ float nm12 = Math.fma(m02, r10, Math.fma(m12, r11, Math.fma(m22, r12, m32 * r13)));
+ float nm13 = Math.fma(m03, r10, Math.fma(m13, r11, Math.fma(m23, r12, m33 * r13)));
+ float nm20 = Math.fma(m00, r20, Math.fma(m10, r21, Math.fma(m20, r22, m30 * r23)));
+ float nm21 = Math.fma(m01, r20, Math.fma(m11, r21, Math.fma(m21, r22, m31 * r23)));
+ float nm22 = Math.fma(m02, r20, Math.fma(m12, r21, Math.fma(m22, r22, m32 * r23)));
+ float nm23 = Math.fma(m03, r20, Math.fma(m13, r21, Math.fma(m23, r22, m33 * r23)));
+ float nm30 = Math.fma(m00, r30, Math.fma(m10, r31, Math.fma(m20, r32, m30 * r33)));
+ float nm31 = Math.fma(m01, r30, Math.fma(m11, r31, Math.fma(m21, r32, m31 * r33)));
+ float nm32 = Math.fma(m02, r30, Math.fma(m12, r31, Math.fma(m22, r32, m32 * r33)));
+ float nm33 = Math.fma(m03, r30, Math.fma(m13, r31, Math.fma(m23, r32, m33 * r33)));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Multiply this matrix by the 3x3 matrix with the supplied elements expanded to a 4x4 matrix with
+ * all other matrix elements set to identity.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @return this
+ */
+ public Matrix4f mul3x3(
+ float r00, float r01, float r02,
+ float r10, float r11, float r12,
+ float r20, float r21, float r22) {
+ return mul3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, this);
+ }
+ public Matrix4f mul3x3(
+ float r00, float r01, float r02,
+ float r10, float r11, float r12,
+ float r20, float r21, float r22, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(r00, r01, r02, 0, r10, r11, r12, 0, r20, r21, r22, 0, 0, 0, 0, 1);
+ return mulGeneric3x3(r00, r01, r02, r10, r11, r12, r20, r21, r22, dest);
+ }
+ private Matrix4f mulGeneric3x3(
+ float r00, float r01, float r02,
+ float r10, float r11, float r12,
+ float r20, float r21, float r22, Matrix4f dest) {
+ float nm00 = Math.fma(m00, r00, Math.fma(m10, r01, m20 * r02));
+ float nm01 = Math.fma(m01, r00, Math.fma(m11, r01, m21 * r02));
+ float nm02 = Math.fma(m02, r00, Math.fma(m12, r01, m22 * r02));
+ float nm03 = Math.fma(m03, r00, Math.fma(m13, r01, m23 * r02));
+ float nm10 = Math.fma(m00, r10, Math.fma(m10, r11, m20 * r12));
+ float nm11 = Math.fma(m01, r10, Math.fma(m11, r11, m21 * r12));
+ float nm12 = Math.fma(m02, r10, Math.fma(m12, r11, m22 * r12));
+ float nm13 = Math.fma(m03, r10, Math.fma(m13, r11, m23 * r12));
+ float nm20 = Math.fma(m00, r20, Math.fma(m10, r21, m20 * r22));
+ float nm21 = Math.fma(m01, r20, Math.fma(m11, r21, m21 * r22));
+ float nm22 = Math.fma(m02, r20, Math.fma(m12, r21, m22 * r22));
+ float nm23 = Math.fma(m03, r20, Math.fma(m13, r21, m23 * r22));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(this.properties & PROPERTY_AFFINE);
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4f mulLocal(Matrix4fc left) {
+ return mulLocal(left, this);
+ }
+
+ public Matrix4f mulLocal(Matrix4fc left, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(left);
+ else if ((left.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_AFFINE) != 0 && (left.properties() & PROPERTY_AFFINE) != 0)
+ return mulLocalAffine(left, dest);
+ return mulLocalGeneric(left, dest);
+ }
+ private Matrix4f mulLocalGeneric(Matrix4fc left, Matrix4f dest) {
+ float nm00 = Math.fma(left.m00(), m00, Math.fma(left.m10(), m01, Math.fma(left.m20(), m02, left.m30() * m03)));
+ float nm01 = Math.fma(left.m01(), m00, Math.fma(left.m11(), m01, Math.fma(left.m21(), m02, left.m31() * m03)));
+ float nm02 = Math.fma(left.m02(), m00, Math.fma(left.m12(), m01, Math.fma(left.m22(), m02, left.m32() * m03)));
+ float nm03 = Math.fma(left.m03(), m00, Math.fma(left.m13(), m01, Math.fma(left.m23(), m02, left.m33() * m03)));
+ float nm10 = Math.fma(left.m00(), m10, Math.fma(left.m10(), m11, Math.fma(left.m20(), m12, left.m30() * m13)));
+ float nm11 = Math.fma(left.m01(), m10, Math.fma(left.m11(), m11, Math.fma(left.m21(), m12, left.m31() * m13)));
+ float nm12 = Math.fma(left.m02(), m10, Math.fma(left.m12(), m11, Math.fma(left.m22(), m12, left.m32() * m13)));
+ float nm13 = Math.fma(left.m03(), m10, Math.fma(left.m13(), m11, Math.fma(left.m23(), m12, left.m33() * m13)));
+ float nm20 = Math.fma(left.m00(), m20, Math.fma(left.m10(), m21, Math.fma(left.m20(), m22, left.m30() * m23)));
+ float nm21 = Math.fma(left.m01(), m20, Math.fma(left.m11(), m21, Math.fma(left.m21(), m22, left.m31() * m23)));
+ float nm22 = Math.fma(left.m02(), m20, Math.fma(left.m12(), m21, Math.fma(left.m22(), m22, left.m32() * m23)));
+ float nm23 = Math.fma(left.m03(), m20, Math.fma(left.m13(), m21, Math.fma(left.m23(), m22, left.m33() * m23)));
+ float nm30 = Math.fma(left.m00(), m30, Math.fma(left.m10(), m31, Math.fma(left.m20(), m32, left.m30() * m33)));
+ float nm31 = Math.fma(left.m01(), m30, Math.fma(left.m11(), m31, Math.fma(left.m21(), m32, left.m31() * m33)));
+ float nm32 = Math.fma(left.m02(), m30, Math.fma(left.m12(), m31, Math.fma(left.m22(), m32, left.m32() * m33)));
+ float nm33 = Math.fma(left.m03(), m30, Math.fma(left.m13(), m31, Math.fma(left.m23(), m32, left.m33() * m33)));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in this
.
+ *
+ * This method assumes that this
matrix and the given left
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of left
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @return this
+ */
+ public Matrix4f mulLocalAffine(Matrix4fc left) {
+ return mulLocalAffine(left, this);
+ }
+
+ public Matrix4f mulLocalAffine(Matrix4fc left, Matrix4f dest) {
+ float nm00 = left.m00() * m00 + left.m10() * m01 + left.m20() * m02;
+ float nm01 = left.m01() * m00 + left.m11() * m01 + left.m21() * m02;
+ float nm02 = left.m02() * m00 + left.m12() * m01 + left.m22() * m02;
+ float nm03 = left.m03();
+ float nm10 = left.m00() * m10 + left.m10() * m11 + left.m20() * m12;
+ float nm11 = left.m01() * m10 + left.m11() * m11 + left.m21() * m12;
+ float nm12 = left.m02() * m10 + left.m12() * m11 + left.m22() * m12;
+ float nm13 = left.m13();
+ float nm20 = left.m00() * m20 + left.m10() * m21 + left.m20() * m22;
+ float nm21 = left.m01() * m20 + left.m11() * m21 + left.m21() * m22;
+ float nm22 = left.m02() * m20 + left.m12() * m21 + left.m22() * m22;
+ float nm23 = left.m23();
+ float nm30 = left.m00() * m30 + left.m10() * m31 + left.m20() * m32 + left.m30();
+ float nm31 = left.m01() * m30 + left.m11() * m31 + left.m21() * m32 + left.m31();
+ float nm32 = left.m02() * m30 + left.m12() * m31 + left.m22() * m32 + left.m32();
+ float nm33 = left.m33();
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(PROPERTY_AFFINE | (this.properties() & left.properties() & PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4f mul(Matrix4x3fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4f mul(Matrix4x3fc right, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return mulTranslation(right, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return mulAffine(right, dest);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return mulPerspectiveAffine(right, dest);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4f mulTranslation(Matrix4x3fc right, Matrix4f dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m03(m03)
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m13(m13)
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m23(m23)
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (right.properties() & PROPERTY_ORTHONORMAL));
+ }
+ private Matrix4f mulAffine(Matrix4x3fc right, Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ float m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ float rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ float rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ float rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ float rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m03(m03)
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m13(m13)
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m23(m23)
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (this.properties & right.properties() & PROPERTY_ORTHONORMAL));
+ }
+ private Matrix4f mulGeneric(Matrix4x3fc right, Matrix4f dest) {
+ float nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ float nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ float nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ float nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), m23 * right.m02()));
+ float nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ float nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ float nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ float nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), m23 * right.m12()));
+ float nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ float nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ float nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ float nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), m23 * right.m22()));
+ float nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30)));
+ float nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31)));
+ float nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32)));
+ float nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33)));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4f mul(Matrix3x2fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4f mul(Matrix3x2fc right, Matrix4f dest) {
+ float nm00 = m00 * right.m00() + m10 * right.m01();
+ float nm01 = m01 * right.m00() + m11 * right.m01();
+ float nm02 = m02 * right.m00() + m12 * right.m01();
+ float nm03 = m03 * right.m00() + m13 * right.m01();
+ float nm10 = m00 * right.m10() + m10 * right.m11();
+ float nm11 = m01 * right.m10() + m11 * right.m11();
+ float nm12 = m02 * right.m10() + m12 * right.m11();
+ float nm13 = m03 * right.m10() + m13 * right.m11();
+ float nm30 = m00 * right.m20() + m10 * right.m21() + m30;
+ float nm31 = m01 * right.m20() + m11 * right.m21() + m31;
+ float nm32 = m02 * right.m20() + m12 * right.m21() + m32;
+ float nm33 = m03 * right.m20() + m13 * right.m21() + m33;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied {@link #isAffine() affine} view
matrix.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the {@link #isAffine() affine} matrix to multiply this
symmetric perspective projection matrix by
+ * @return this
+ */
+ public Matrix4f mulPerspectiveAffine(Matrix4fc view) {
+ return mulPerspectiveAffine(view, this);
+ }
+
+ public Matrix4f mulPerspectiveAffine(Matrix4fc view, Matrix4f dest) {
+ float nm00 = m00 * view.m00(), nm01 = m11 * view.m01(), nm02 = m22 * view.m02(), nm03 = m23 * view.m02();
+ float nm10 = m00 * view.m10(), nm11 = m11 * view.m11(), nm12 = m22 * view.m12(), nm13 = m23 * view.m12();
+ float nm20 = m00 * view.m20(), nm21 = m11 * view.m21(), nm22 = m22 * view.m22(), nm23 = m23 * view.m22();
+ float nm30 = m00 * view.m30(), nm31 = m11 * view.m31(), nm32 = m22 * view.m32() + m32, nm33 = m23 * view.m32();
+ return dest
+ ._m00(nm00)._m01(nm01)._m02(nm02)._m03(nm03)
+ ._m10(nm10)._m11(nm11)._m12(nm12)._m13(nm13)
+ ._m20(nm20)._m21(nm21)._m22(nm22)._m23(nm23)
+ ._m30(nm30)._m31(nm31)._m32(nm32)._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied view
matrix.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix to multiply this
symmetric perspective projection matrix by
+ * @return this
+ */
+ public Matrix4f mulPerspectiveAffine(Matrix4x3fc view) {
+ return mulPerspectiveAffine(view, this);
+ }
+
+ public Matrix4f mulPerspectiveAffine(Matrix4x3fc view, Matrix4f dest) {
+ float lm00 = m00, lm11 = m11, lm22 = m22, lm23 = m23;
+ return dest.
+ _m00(lm00 * view.m00())._m01(lm11 * view.m01())._m02(lm22 * view.m02())._m03(lm23 * view.m02()).
+ _m10(lm00 * view.m10())._m11(lm11 * view.m11())._m12(lm22 * view.m12())._m13(lm23 * view.m12()).
+ _m20(lm00 * view.m20())._m21(lm11 * view.m21())._m22(lm22 * view.m22())._m23(lm23 * view.m22()).
+ _m30(lm00 * view.m30())._m31(lm11 * view.m31())._m32(lm22 * view.m32() + m32)._m33(lm23 * view.m32()).
+ _properties(0);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, which is assumed to be {@link #isAffine() affine}, and store the result in this
.
+ *
+ * This method assumes that the given right
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @return this
+ */
+ public Matrix4f mulAffineR(Matrix4fc right) {
+ return mulAffineR(right, this);
+ }
+
+ public Matrix4f mulAffineR(Matrix4fc right, Matrix4f dest) {
+ float nm00 = Math.fma(m00, right.m00(), Math.fma(m10, right.m01(), m20 * right.m02()));
+ float nm01 = Math.fma(m01, right.m00(), Math.fma(m11, right.m01(), m21 * right.m02()));
+ float nm02 = Math.fma(m02, right.m00(), Math.fma(m12, right.m01(), m22 * right.m02()));
+ float nm03 = Math.fma(m03, right.m00(), Math.fma(m13, right.m01(), m23 * right.m02()));
+ float nm10 = Math.fma(m00, right.m10(), Math.fma(m10, right.m11(), m20 * right.m12()));
+ float nm11 = Math.fma(m01, right.m10(), Math.fma(m11, right.m11(), m21 * right.m12()));
+ float nm12 = Math.fma(m02, right.m10(), Math.fma(m12, right.m11(), m22 * right.m12()));
+ float nm13 = Math.fma(m03, right.m10(), Math.fma(m13, right.m11(), m23 * right.m12()));
+ float nm20 = Math.fma(m00, right.m20(), Math.fma(m10, right.m21(), m20 * right.m22()));
+ float nm21 = Math.fma(m01, right.m20(), Math.fma(m11, right.m21(), m21 * right.m22()));
+ float nm22 = Math.fma(m02, right.m20(), Math.fma(m12, right.m21(), m22 * right.m22()));
+ float nm23 = Math.fma(m03, right.m20(), Math.fma(m13, right.m21(), m23 * right.m22()));
+ float nm30 = Math.fma(m00, right.m30(), Math.fma(m10, right.m31(), Math.fma(m20, right.m32(), m30)));
+ float nm31 = Math.fma(m01, right.m30(), Math.fma(m11, right.m31(), Math.fma(m21, right.m32(), m31)));
+ float nm32 = Math.fma(m02, right.m30(), Math.fma(m12, right.m31(), Math.fma(m22, right.m32(), m32)));
+ float nm33 = Math.fma(m03, right.m30(), Math.fma(m13, right.m31(), Math.fma(m23, right.m32(), m33)));
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_PERSPECTIVE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in this
.
+ *
+ * This method assumes that this
matrix and the given right
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @return this
+ */
+ public Matrix4f mulAffine(Matrix4fc right) {
+ return mulAffine(right, this);
+ }
+
+ public Matrix4f mulAffine(Matrix4fc right, Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ float m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ float rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ float rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ float rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ float rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m03(m03)
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m13(m13)
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m23(m23)
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (this.properties & right.properties() & PROPERTY_ORTHONORMAL));
+ }
+
+ public Matrix4f mulTranslationAffine(Matrix4fc right, Matrix4f dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m03(m03)
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m13(m13)
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m23(m23)
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._m33(m33)
+ ._properties(PROPERTY_AFFINE | (right.properties() & PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied {@link #isAffine() affine} view
matrix.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the affine matrix which to multiply this
with
+ * @return this
+ */
+ public Matrix4f mulOrthoAffine(Matrix4fc view) {
+ return mulOrthoAffine(view, this);
+ }
+
+ public Matrix4f mulOrthoAffine(Matrix4fc view, Matrix4f dest) {
+ float nm00 = m00 * view.m00();
+ float nm01 = m11 * view.m01();
+ float nm02 = m22 * view.m02();
+ float nm10 = m00 * view.m10();
+ float nm11 = m11 * view.m11();
+ float nm12 = m22 * view.m12();
+ float nm20 = m00 * view.m20();
+ float nm21 = m11 * view.m21();
+ float nm22 = m22 * view.m22();
+ float nm30 = m00 * view.m30() + m30;
+ float nm31 = m11 * view.m31() + m31;
+ float nm32 = m22 * view.m32() + m32;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(0.0f)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE);
+ }
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * by first multiplying each component of other
's 4x3 submatrix by otherFactor
and
+ * adding that result to this
.
+ *
+ * The matrix other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's 4x3 components
+ * @return this
+ */
+ public Matrix4f fma4x3(Matrix4fc other, float otherFactor) {
+ return fma4x3(other, otherFactor, this);
+ }
+
+ public Matrix4f fma4x3(Matrix4fc other, float otherFactor, Matrix4f dest) {
+ dest._m00(Math.fma(other.m00(), otherFactor, m00))
+ ._m01(Math.fma(other.m01(), otherFactor, m01))
+ ._m02(Math.fma(other.m02(), otherFactor, m02))
+ ._m03(m03)
+ ._m10(Math.fma(other.m10(), otherFactor, m10))
+ ._m11(Math.fma(other.m11(), otherFactor, m11))
+ ._m12(Math.fma(other.m12(), otherFactor, m12))
+ ._m13(m13)
+ ._m20(Math.fma(other.m20(), otherFactor, m20))
+ ._m21(Math.fma(other.m21(), otherFactor, m21))
+ ._m22(Math.fma(other.m22(), otherFactor, m22))
+ ._m23(m23)
+ ._m30(Math.fma(other.m30(), otherFactor, m30))
+ ._m31(Math.fma(other.m31(), otherFactor, m31))
+ ._m32(Math.fma(other.m32(), otherFactor, m32))
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4f add(Matrix4fc other) {
+ return add(other, this);
+ }
+
+ public Matrix4f add(Matrix4fc other, Matrix4f dest) {
+ dest._m00(m00 + other.m00())
+ ._m01(m01 + other.m01())
+ ._m02(m02 + other.m02())
+ ._m03(m03 + other.m03())
+ ._m10(m10 + other.m10())
+ ._m11(m11 + other.m11())
+ ._m12(m12 + other.m12())
+ ._m13(m13 + other.m13())
+ ._m20(m20 + other.m20())
+ ._m21(m21 + other.m21())
+ ._m22(m22 + other.m22())
+ ._m23(m23 + other.m23())
+ ._m30(m30 + other.m30())
+ ._m31(m31 + other.m31())
+ ._m32(m32 + other.m32())
+ ._m33(m33 + other.m33())
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4f sub(Matrix4fc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix4f sub(Matrix4fc subtrahend, Matrix4f dest) {
+ dest._m00(m00 - subtrahend.m00())
+ ._m01(m01 - subtrahend.m01())
+ ._m02(m02 - subtrahend.m02())
+ ._m03(m03 - subtrahend.m03())
+ ._m10(m10 - subtrahend.m10())
+ ._m11(m11 - subtrahend.m11())
+ ._m12(m12 - subtrahend.m12())
+ ._m13(m13 - subtrahend.m13())
+ ._m20(m20 - subtrahend.m20())
+ ._m21(m21 - subtrahend.m21())
+ ._m22(m22 - subtrahend.m22())
+ ._m23(m23 - subtrahend.m23())
+ ._m30(m30 - subtrahend.m30())
+ ._m31(m31 - subtrahend.m31())
+ ._m32(m32 - subtrahend.m32())
+ ._m33(m33 - subtrahend.m33())
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix4f mulComponentWise(Matrix4fc other) {
+ return mulComponentWise(other, this);
+ }
+
+ public Matrix4f mulComponentWise(Matrix4fc other, Matrix4f dest) {
+ dest._m00(m00 * other.m00())
+ ._m01(m01 * other.m01())
+ ._m02(m02 * other.m02())
+ ._m03(m03 * other.m03())
+ ._m10(m10 * other.m10())
+ ._m11(m11 * other.m11())
+ ._m12(m12 * other.m12())
+ ._m13(m13 * other.m13())
+ ._m20(m20 * other.m20())
+ ._m21(m21 * other.m21())
+ ._m22(m22 * other.m22())
+ ._m23(m23 * other.m23())
+ ._m30(m30 * other.m30())
+ ._m31(m31 * other.m31())
+ ._m32(m32 * other.m32())
+ ._m33(m33 * other.m33())
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4f add4x3(Matrix4fc other) {
+ return add4x3(other, this);
+ }
+
+ public Matrix4f add4x3(Matrix4fc other, Matrix4f dest) {
+ dest._m00(m00 + other.m00())
+ ._m01(m01 + other.m01())
+ ._m02(m02 + other.m02())
+ ._m03(m03)
+ ._m10(m10 + other.m10())
+ ._m11(m11 + other.m11())
+ ._m12(m12 + other.m12())
+ ._m13(m13)
+ ._m20(m20 + other.m20())
+ ._m21(m21 + other.m21())
+ ._m22(m22 + other.m22())
+ ._m23(m23)
+ ._m30(m30 + other.m30())
+ ._m31(m31 + other.m31())
+ ._m32(m32 + other.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract the upper 4x3 submatrices of subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4f sub4x3(Matrix4f subtrahend) {
+ return sub4x3(subtrahend, this);
+ }
+
+ public Matrix4f sub4x3(Matrix4fc subtrahend, Matrix4f dest) {
+ dest._m00(m00 - subtrahend.m00())
+ ._m01(m01 - subtrahend.m01())
+ ._m02(m02 - subtrahend.m02())
+ ._m03(m03)
+ ._m10(m10 - subtrahend.m10())
+ ._m11(m11 - subtrahend.m11())
+ ._m12(m12 - subtrahend.m12())
+ ._m13(m13)
+ ._m20(m20 - subtrahend.m20())
+ ._m21(m21 - subtrahend.m21())
+ ._m22(m22 - subtrahend.m22())
+ ._m23(m23)
+ ._m30(m30 - subtrahend.m30())
+ ._m31(m31 - subtrahend.m31())
+ ._m32(m32 - subtrahend.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply the upper 4x3 submatrices of this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix4f mul4x3ComponentWise(Matrix4fc other) {
+ return mul4x3ComponentWise(other, this);
+ }
+
+ public Matrix4f mul4x3ComponentWise(Matrix4fc other, Matrix4f dest) {
+ dest._m00(m00 * other.m00())
+ ._m01(m01 * other.m01())
+ ._m02(m02 * other.m02())
+ ._m03(m03)
+ ._m10(m10 * other.m10())
+ ._m11(m11 * other.m11())
+ ._m12(m12 * other.m12())
+ ._m13(m13)
+ ._m20(m20 * other.m20())
+ ._m21(m21 * other.m21())
+ ._m22(m22 * other.m22())
+ ._m23(m23)
+ ._m30(m30 * other.m30())
+ ._m31(m31 * other.m31())
+ ._m32(m32 * other.m32())
+ ._m33(m33)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied float values. The matrix will look like this:
+ *
+ * m00, m10, m20, m30
+ * m01, m11, m21, m31
+ * m02, m12, m22, m32
+ * m03, m13, m23, m33
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m02
+ * the new value of m02
+ * @param m03
+ * the new value of m03
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m12
+ * the new value of m12
+ * @param m13
+ * the new value of m13
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @param m22
+ * the new value of m22
+ * @param m23
+ * the new value of m23
+ * @param m30
+ * the new value of m30
+ * @param m31
+ * the new value of m31
+ * @param m32
+ * the new value of m32
+ * @param m33
+ * the new value of m33
+ * @return this
+ */
+ public Matrix4f set(float m00, float m01, float m02, float m03,
+ float m10, float m11, float m12, float m13,
+ float m20, float m21, float m22, float m23,
+ float m30, float m31, float m32, float m33) {
+ return this
+ ._m00(m00)
+ ._m10(m10)
+ ._m20(m20)
+ ._m30(m30)
+ ._m01(m01)
+ ._m11(m11)
+ ._m21(m21)
+ ._m31(m31)
+ ._m02(m02)
+ ._m12(m12)
+ ._m22(m22)
+ ._m32(m32)
+ ._m03(m03)
+ ._m13(m13)
+ ._m23(m23)
+ ._m33(m33)
+ .determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 4, 8, 12
+ * 1, 5, 9, 13
+ * 2, 6, 10, 14
+ * 3, 7, 11, 15
+ *
+ * @see #set(float[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4f set(float m[], int off) {
+ MemUtil.INSTANCE.copy(m, off, this);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 4, 8, 12
+ * 1, 5, 9, 13
+ * 2, 6, 10, 14
+ * 3, 7, 11, 15
+ *
+ * @see #set(float[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4f set(float m[]) {
+ return set(m, 0);
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in row-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 1, 2, 3
+ * 4, 5, 6, 7
+ * 8, 9, 10, 11
+ * 12, 13, 14, 15
+ *
+ * @see #setTransposed(float[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4f setTransposed(float m[], int off) {
+ MemUtil.INSTANCE.copyTransposed(m, off, this);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in row-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 1, 2, 3
+ * 4, 5, 6, 7
+ * 8, 9, 10, 11
+ * 12, 13, 14, 15
+ *
+ * @see #setTransposed(float[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4f setTransposed(float m[]) {
+ return setTransposed(m, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link FloatBuffer} in row-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in row-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in row-major order
+ * @return this
+ */
+ public Matrix4f setTransposed(FloatBuffer buffer) {
+ MemUtil.INSTANCE.getTransposed(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from the given {@link ByteBuffer} in row-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in row-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in row-major order
+ * @return this
+ */
+ public Matrix4f setTransposed(ByteBuffer buffer) {
+ MemUtil.INSTANCE.getTransposed(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 16 float values from off-heap memory in row-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in row-major order
+ * @return this
+ */
+ public Matrix4f setTransposedFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.getTransposed(this, address);
+ return determineProperties();
+ }
+
+ /**
+ * Set the four columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ * @return this
+ */
+ public Matrix4f set(Vector4fc col0, Vector4fc col1, Vector4fc col2, Vector4fc col3) {
+ return
+ _m00(col0.x()).
+ _m01(col0.y()).
+ _m02(col0.z()).
+ _m03(col0.w()).
+ _m10(col1.x()).
+ _m11(col1.y()).
+ _m12(col1.z()).
+ _m13(col1.w()).
+ _m20(col2.x()).
+ _m21(col2.y()).
+ _m22(col2.z()).
+ _m23(col2.w()).
+ _m30(col3.x()).
+ _m31(col3.y()).
+ _m32(col3.z()).
+ _m33(col3.w()).
+ determineProperties();
+ }
+
+ public float determinant() {
+ if ((properties & PROPERTY_AFFINE) != 0)
+ return determinantAffine();
+ return (m00 * m11 - m01 * m10) * (m22 * m33 - m23 * m32)
+ + (m02 * m10 - m00 * m12) * (m21 * m33 - m23 * m31)
+ + (m00 * m13 - m03 * m10) * (m21 * m32 - m22 * m31)
+ + (m01 * m12 - m02 * m11) * (m20 * m33 - m23 * m30)
+ + (m03 * m11 - m01 * m13) * (m20 * m32 - m22 * m30)
+ + (m02 * m13 - m03 * m12) * (m20 * m31 - m21 * m30);
+ }
+
+ public float determinant3x3() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ public float determinantAffine() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ public Matrix4f invert(Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0) {
+ return dest.identity();
+ } else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return invertTranslation(dest);
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return invertOrthonormal(dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return invertAffine(dest);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return invertPerspective(dest);
+ return invertGeneric(dest);
+ }
+ private Matrix4f invertTranslation(Matrix4f dest) {
+ if (dest != this)
+ dest.set(this);
+ return dest._m30(-m30)._m31(-m31)._m32(-m32)._properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ }
+ private Matrix4f invertOrthonormal(Matrix4f dest) {
+ float nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
+ float nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
+ float nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
+ float m01 = this.m01;
+ float m02 = this.m02;
+ float m12 = this.m12;
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m03(0.0f)
+ ._m10(m01)
+ ._m11(m11)
+ ._m12(m21)
+ ._m13(0.0f)
+ ._m20(m02)
+ ._m21(m12)
+ ._m22(m22)
+ ._m23(0.0f)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+ private Matrix4f invertGeneric(Matrix4f dest) {
+ if (this != dest)
+ return invertGenericNonThis(dest);
+ return invertGenericThis(dest);
+ }
+ private Matrix4f invertGenericNonThis(Matrix4f dest) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float c = m00 * m13 - m03 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float e = m01 * m13 - m03 * m11;
+ float f = m02 * m13 - m03 * m12;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float i = m20 * m33 - m23 * m30;
+ float j = m21 * m32 - m22 * m31;
+ float k = m21 * m33 - m23 * m31;
+ float l = m22 * m33 - m23 * m32;
+ float det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0f / det;
+ return dest
+ ._m00(Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det)
+ ._m01(Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det)
+ ._m02(Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det)
+ ._m03(Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det)
+ ._m10(Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det)
+ ._m11(Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det)
+ ._m12(Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det)
+ ._m13(Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det)
+ ._m20(Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det)
+ ._m21(Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det)
+ ._m22(Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det)
+ ._m23(Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det)
+ ._m30(Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det)
+ ._m31(Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det)
+ ._m32(Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det)
+ ._m33(Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det)
+ ._properties(0);
+ }
+ private Matrix4f invertGenericThis(Matrix4f dest) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float c = m00 * m13 - m03 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float e = m01 * m13 - m03 * m11;
+ float f = m02 * m13 - m03 * m12;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float i = m20 * m33 - m23 * m30;
+ float j = m21 * m32 - m22 * m31;
+ float k = m21 * m33 - m23 * m31;
+ float l = m22 * m33 - m23 * m32;
+ float det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0f / det;
+ float nm00 = Math.fma( m11, l, Math.fma(-m12, k, m13 * j)) * det;
+ float nm01 = Math.fma(-m01, l, Math.fma( m02, k, -m03 * j)) * det;
+ float nm02 = Math.fma( m31, f, Math.fma(-m32, e, m33 * d)) * det;
+ float nm03 = Math.fma(-m21, f, Math.fma( m22, e, -m23 * d)) * det;
+ float nm10 = Math.fma(-m10, l, Math.fma( m12, i, -m13 * h)) * det;
+ float nm11 = Math.fma( m00, l, Math.fma(-m02, i, m03 * h)) * det;
+ float nm12 = Math.fma(-m30, f, Math.fma( m32, c, -m33 * b)) * det;
+ float nm13 = Math.fma( m20, f, Math.fma(-m22, c, m23 * b)) * det;
+ float nm20 = Math.fma( m10, k, Math.fma(-m11, i, m13 * g)) * det;
+ float nm21 = Math.fma(-m00, k, Math.fma( m01, i, -m03 * g)) * det;
+ float nm22 = Math.fma( m30, e, Math.fma(-m31, c, m33 * a)) * det;
+ float nm23 = Math.fma(-m20, e, Math.fma( m21, c, -m23 * a)) * det;
+ float nm30 = Math.fma(-m10, j, Math.fma( m11, h, -m12 * g)) * det;
+ float nm31 = Math.fma( m00, j, Math.fma(-m01, h, m02 * g)) * det;
+ float nm32 = Math.fma(-m30, d, Math.fma( m31, b, -m32 * a)) * det;
+ float nm33 = Math.fma( m20, d, Math.fma(-m21, b, m22 * a)) * det;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * If this
matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing,
+ * and thus its last row is equal to (0, 0, 0, 1)
, then {@link #invertAffine()} can be used instead of this method.
+ *
+ * @see #invertAffine()
+ *
+ * @return this
+ */
+ public Matrix4f invert() {
+ return invert(this);
+ }
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float) perspective()} methods
+ * or via {@link #setPerspective(float, float, float, float) setPerspective()}, that is, if this
is a symmetrical perspective frustum transformation,
+ * then this method builds the inverse of this
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix when being obtained via {@link #perspective(float, float, float, float) perspective()}.
+ *
+ * @see #perspective(float, float, float, float)
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ public Matrix4f invertPerspective(Matrix4f dest) {
+ float a = 1.0f / (m00 * m11);
+ float l = -1.0f / (m23 * m32);
+ return dest
+ .set(m11 * a, 0, 0, 0,
+ 0, m00 * a, 0, 0,
+ 0, 0, 0, -m23 * l,
+ 0, 0, -m32 * l, m22 * l)
+ ._properties(0);
+ }
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float) perspective()} methods
+ * or via {@link #setPerspective(float, float, float, float) setPerspective()}, that is, if this
is a symmetrical perspective frustum transformation,
+ * then this method builds the inverse of this
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix when being obtained via {@link #perspective(float, float, float, float) perspective()}.
+ *
+ * @see #perspective(float, float, float, float)
+ *
+ * @return this
+ */
+ public Matrix4f invertPerspective() {
+ return invertPerspective(this);
+ }
+
+ /**
+ * If this
is an arbitrary perspective projection matrix obtained via one of the {@link #frustum(float, float, float, float, float, float) frustum()} methods
+ * or via {@link #setFrustum(float, float, float, float, float, float) setFrustum()},
+ * then this method builds the inverse of this
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix.
+ *
+ * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(float, float, float, float) perspective()}, then
+ * {@link #invertPerspective(Matrix4f)} should be used instead.
+ *
+ * @see #frustum(float, float, float, float, float, float)
+ * @see #invertPerspective(Matrix4f)
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ public Matrix4f invertFrustum(Matrix4f dest) {
+ float invM00 = 1.0f / m00;
+ float invM11 = 1.0f / m11;
+ float invM23 = 1.0f / m23;
+ float invM32 = 1.0f / m32;
+ return dest
+ .set(invM00, 0, 0, 0,
+ 0, invM11, 0, 0,
+ 0, 0, 0, invM32,
+ -m20 * invM00 * invM23, -m21 * invM11 * invM23, invM23, -m22 * invM23 * invM32);
+ }
+
+ /**
+ * If this
is an arbitrary perspective projection matrix obtained via one of the {@link #frustum(float, float, float, float, float, float) frustum()} methods
+ * or via {@link #setFrustum(float, float, float, float, float, float) setFrustum()},
+ * then this method builds the inverse of this
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix.
+ *
+ * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(float, float, float, float) perspective()}, then
+ * {@link #invertPerspective()} should be used instead.
+ *
+ * @see #frustum(float, float, float, float, float, float)
+ * @see #invertPerspective()
+ *
+ * @return this
+ */
+ public Matrix4f invertFrustum() {
+ return invertFrustum(this);
+ }
+
+ public Matrix4f invertOrtho(Matrix4f dest) {
+ float invM00 = 1.0f / m00;
+ float invM11 = 1.0f / m11;
+ float invM22 = 1.0f / m22;
+ return dest
+ .set(invM00, 0, 0, 0,
+ 0, invM11, 0, 0,
+ 0, 0, invM22, 0,
+ -m30 * invM00, -m31 * invM11, -m32 * invM22, 1)
+ ._properties(PROPERTY_AFFINE | (this.properties & PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Invert this
orthographic projection matrix.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @return this
+ */
+ public Matrix4f invertOrtho() {
+ return invertOrtho(this);
+ }
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float) perspective()} methods
+ * or via {@link #setPerspective(float, float, float, float) setPerspective()}, that is, if this
is a symmetrical perspective frustum transformation
+ * and the given view
matrix is {@link #isAffine() affine} and has unit scaling (for example by being obtained via {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()}),
+ * then this method builds the inverse of this * view
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of the combination of the view and projection matrices, when both were obtained
+ * via the common methods {@link #perspective(float, float, float, float) perspective()} and {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()} or
+ * other methods, that build affine matrices, such as {@link #translate(float, float, float) translate} and {@link #rotate(float, float, float, float)}, except for {@link #scale(float, float, float) scale()}.
+ *
+ * For the special cases of the matrices this
and view
mentioned above, this method is equivalent to the following code:
+ *
+ * dest.set(this).mul(view).invert();
+ *
+ *
+ * @param view
+ * the view transformation (must be {@link #isAffine() affine} and have unit scaling)
+ * @param dest
+ * will hold the inverse of this * view
+ * @return dest
+ */
+ public Matrix4f invertPerspectiveView(Matrix4fc view, Matrix4f dest) {
+ float a = 1.0f / (m00 * m11);
+ float l = -1.0f / (m23 * m32);
+ float pm00 = m11 * a;
+ float pm11 = m00 * a;
+ float pm23 = -m23 * l;
+ float pm32 = -m32 * l;
+ float pm33 = m22 * l;
+ float vm30 = -view.m00() * view.m30() - view.m01() * view.m31() - view.m02() * view.m32();
+ float vm31 = -view.m10() * view.m30() - view.m11() * view.m31() - view.m12() * view.m32();
+ float vm32 = -view.m20() * view.m30() - view.m21() * view.m31() - view.m22() * view.m32();
+ float nm10 = view.m01() * pm11;
+ float nm30 = view.m02() * pm32 + vm30 * pm33;
+ float nm31 = view.m12() * pm32 + vm31 * pm33;
+ float nm32 = view.m22() * pm32 + vm32 * pm33;
+ return dest
+ ._m00(view.m00() * pm00)
+ ._m01(view.m10() * pm00)
+ ._m02(view.m20() * pm00)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(view.m11() * pm11)
+ ._m12(view.m21() * pm11)
+ ._m13(0.0f)
+ ._m20(vm30 * pm23)
+ ._m21(vm31 * pm23)
+ ._m22(vm32 * pm23)
+ ._m23(pm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(pm33)
+ ._properties(0);
+ }
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float) perspective()} methods
+ * or via {@link #setPerspective(float, float, float, float) setPerspective()}, that is, if this
is a symmetrical perspective frustum transformation
+ * and the given view
matrix has unit scaling,
+ * then this method builds the inverse of this * view
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of the combination of the view and projection matrices, when both were obtained
+ * via the common methods {@link #perspective(float, float, float, float) perspective()} and {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()} or
+ * other methods, that build affine matrices, such as {@link #translate(float, float, float) translate} and {@link #rotate(float, float, float, float)}, except for {@link #scale(float, float, float) scale()}.
+ *
+ * For the special cases of the matrices this
and view
mentioned above, this method is equivalent to the following code:
+ *
+ * dest.set(this).mul(view).invert();
+ *
+ *
+ * @param view
+ * the view transformation (must have unit scaling)
+ * @param dest
+ * will hold the inverse of this * view
+ * @return dest
+ */
+ public Matrix4f invertPerspectiveView(Matrix4x3fc view, Matrix4f dest) {
+ float a = 1.0f / (m00 * m11);
+ float l = -1.0f / (m23 * m32);
+ float pm00 = m11 * a;
+ float pm11 = m00 * a;
+ float pm23 = -m23 * l;
+ float pm32 = -m32 * l;
+ float pm33 = m22 * l;
+ float vm30 = -view.m00() * view.m30() - view.m01() * view.m31() - view.m02() * view.m32();
+ float vm31 = -view.m10() * view.m30() - view.m11() * view.m31() - view.m12() * view.m32();
+ float vm32 = -view.m20() * view.m30() - view.m21() * view.m31() - view.m22() * view.m32();
+ return dest
+ ._m00(view.m00() * pm00)
+ ._m01(view.m10() * pm00)
+ ._m02(view.m20() * pm00)
+ ._m03(0.0f)
+ ._m10(view.m01() * pm11)
+ ._m11(view.m11() * pm11)
+ ._m12(view.m21() * pm11)
+ ._m13(0.0f)
+ ._m20(vm30 * pm23)
+ ._m21(vm31 * pm23)
+ ._m22(vm32 * pm23)
+ ._m23(pm23)
+ ._m30(view.m02() * pm32 + vm30 * pm33)
+ ._m31(view.m12() * pm32 + vm31 * pm33)
+ ._m32(view.m22() * pm32 + vm32 * pm33)
+ ._m33(pm33)
+ ._properties(0);
+ }
+
+ public Matrix4f invertAffine(Matrix4f dest) {
+ float m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
+ float m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
+ float det = (m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20;
+ float s = 1.0f / det;
+ float m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
+ float m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
+ float m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
+ float m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
+ float nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
+ float nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
+ return dest
+ ._m00((m11m22 - m12m21) * s)
+ ._m01((m21m02 - m22m01) * s)
+ ._m02((m12m01 - m11m02) * s)
+ ._m03(0.0f)
+ ._m10((m12m20 - m10m22) * s)
+ ._m11((m22m00 - m20m02) * s)
+ ._m12((m10m02 - m12m00) * s)
+ ._m13(0.0f)
+ ._m20((m10m21 - m11m20) * s)
+ ._m21((m20m01 - m21m00) * s)
+ ._m22((m11m00 - m10m01) * s)
+ ._m23(0.0f)
+ ._m30((m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE);
+ }
+
+ /**
+ * Invert this matrix by assuming that it is an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
).
+ *
+ * @return this
+ */
+ public Matrix4f invertAffine() {
+ return invertAffine(this);
+ }
+
+ public Matrix4f transpose(Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if (this != dest)
+ return transposeNonThisGeneric(dest);
+ return transposeThisGeneric(dest);
+ }
+ private Matrix4f transposeNonThisGeneric(Matrix4f dest) {
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m03(m30)
+ ._m10(m01)
+ ._m11(m11)
+ ._m12(m21)
+ ._m13(m31)
+ ._m20(m02)
+ ._m21(m12)
+ ._m22(m22)
+ ._m23(m32)
+ ._m30(m03)
+ ._m31(m13)
+ ._m32(m23)
+ ._m33(m33)
+ ._properties(0);
+ }
+ private Matrix4f transposeThisGeneric(Matrix4f dest) {
+ float nm10 = m01;
+ float nm20 = m02;
+ float nm21 = m12;
+ float nm30 = m03;
+ float nm31 = m13;
+ float nm32 = m23;
+ return dest
+ ._m01(m10)
+ ._m02(m20)
+ ._m03(m30)
+ ._m10(nm10)
+ ._m12(m21)
+ ._m13(m31)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m23(m32)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._properties(0);
+ }
+
+ /**
+ * Transpose only the upper left 3x3 submatrix of this matrix.
+ *
+ * All other matrix elements are left unchanged.
+ *
+ * @return this
+ */
+ public Matrix4f transpose3x3() {
+ return transpose3x3(this);
+ }
+
+ public Matrix4f transpose3x3(Matrix4f dest) {
+ float nm10 = m01, nm20 = m02, nm21 = m12;
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m10(nm10)
+ ._m11(m11)
+ ._m12(m21)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(m22)
+ ._properties(this.properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ public Matrix3f transpose3x3(Matrix3f dest) {
+ return dest
+ ._m00(m00)
+ ._m01(m10)
+ ._m02(m20)
+ ._m10(m01)
+ ._m11(m11)
+ ._m12(m21)
+ ._m20(m02)
+ ._m21(m12)
+ ._m22(m22);
+ }
+
+ /**
+ * Transpose this matrix.
+ *
+ * @return this
+ */
+ public Matrix4f transpose() {
+ return transpose(this);
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to post-multiply a translation transformation directly to a
+ * matrix, use {@link #translate(float, float, float) translate()} instead.
+ *
+ * @see #translate(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4f translation(float x, float y, float z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ return this._m30(x)._m31(y)._m32(z)._properties(PROPERTY_AFFINE | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to post-multiply a translation transformation directly to a
+ * matrix, use {@link #translate(Vector3fc) translate()} instead.
+ *
+ * @see #translate(float, float, float)
+ *
+ * @param offset
+ * the offsets in x, y and z to translate
+ * @return this
+ */
+ public Matrix4f translation(Vector3fc offset) {
+ return translation(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the given values (x, y, z)
.
+ *
+ * Note that this will only work properly for orthogonal matrices (without any perspective).
+ *
+ * To build a translation matrix instead, use {@link #translation(float, float, float)}.
+ * To apply a translation, use {@link #translate(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ * @see #translate(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4f setTranslation(float x, float y, float z) {
+ return this._m30(x)._m31(y)._m32(z)._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY));
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the values (xyz.x, xyz.y, xyz.z)
.
+ *
+ * Note that this will only work properly for orthogonal matrices (without any perspective).
+ *
+ * To build a translation matrix instead, use {@link #translation(Vector3fc)}.
+ * To apply a translation, use {@link #translate(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ * @see #translate(Vector3fc)
+ *
+ * @param xyz
+ * the units to translate in (x, y, z)
+ * @return this
+ */
+ public Matrix4f setTranslation(Vector3fc xyz) {
+ return setTranslation(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ public Vector3f getTranslation(Vector3f dest) {
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ return dest;
+ }
+
+ public Vector3f getScale(Vector3f dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + " " + Runtime.format(m30, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + " " + Runtime.format(m31, formatter) + "\n"
+ + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + " " + Runtime.format(m32, formatter) + "\n"
+ + Runtime.format(m03, formatter) + " " + Runtime.format(m13, formatter) + " " + Runtime.format(m23, formatter) + " " + Runtime.format(m33, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix4fc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix4fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix4f get(Matrix4f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4x3f get4x3(Matrix4x3f dest) {
+ return dest.set(this);
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix4dc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix4dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix4d get(Matrix4d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3f get3x3(Matrix3f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3d get3x3(Matrix3d dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4f getRotation(AxisAngle4f dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4d getRotation(AxisAngle4d dest) {
+ return dest.set(this);
+ }
+
+ public Quaternionf getUnnormalizedRotation(Quaternionf dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaternionf getNormalizedRotation(Quaternionf dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaterniond getNormalizedRotation(Quaterniond dest) {
+ return dest.setFromNormalized(this);
+ }
+
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get4x3(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x3(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get4x3(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x3(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get4x3(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x3(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get4x3(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x3(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get3x4(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get3x4(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get3x4(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get3x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer getTransposed(FloatBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer getTransposed(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get4x3Transposed(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x3Transposed(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get4x3Transposed(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x3Transposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get4x3Transposed(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x3Transposed(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get4x3Transposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x3Transposed(this, index, buffer);
+ return buffer;
+ }
+ public Matrix4fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public float[] get(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ public float[] get(float[] arr) {
+ MemUtil.INSTANCE.copy(this, arr, 0);
+ return arr;
+ }
+
+ /**
+ * Set all the values within this matrix to 0
.
+ *
+ * @return this
+ */
+ public Matrix4f zero() {
+ MemUtil.INSTANCE.zero(this);
+ return _properties(0);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(float) scale()} instead.
+ *
+ * @see #scale(float)
+ *
+ * @param factor
+ * the scale factor in x, y and z
+ * @return this
+ */
+ public Matrix4f scaling(float factor) {
+ return scaling(factor, factor, factor);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(float, float, float) scale()} instead.
+ *
+ * @see #scale(float, float, float)
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @param z
+ * the scale in z
+ * @return this
+ */
+ public Matrix4f scaling(float x, float y, float z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ return this
+ ._m00(x)
+ ._m11(y)
+ ._m22(z)
+ ._properties(PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0));
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by xyz.x
, xyz.y
and xyz.z
respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector3fc) scale()} instead.
+ *
+ * @see #scale(Vector3fc)
+ *
+ * @param xyz
+ * the scale in x, y and z respectively
+ * @return this
+ */
+ public Matrix4f scaling(Vector3fc xyz) {
+ return scaling(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(float, Vector3fc) rotate()} instead.
+ *
+ * @see #rotate(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4f rotation(float angle, Vector3fc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4f) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4f rotation(AxisAngle4f axisAngle) {
+ return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(float, float, float, float) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the rotation axis
+ * @param y
+ * the y-component of the rotation axis
+ * @param z
+ * the z-component of the rotation axis
+ * @return this
+ */
+ public Matrix4f rotation(float angle, float x, float y, float z) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotationX(x * angle);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotationY(y * angle);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotationZ(z * angle);
+ return rotationInternal(angle, x, y, z);
+ }
+ private Matrix4f rotationInternal(float angle, float x, float y, float z) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float C = 1.0f - cos, xy = x * y, xz = x * z, yz = y * z;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ return this
+ ._m00(cos + x * x * C)
+ ._m10(xy * C - z * sin)
+ ._m20(xz * C + y * sin)
+ ._m01(xy * C + z * sin)
+ ._m11(cos + y * y * C)
+ ._m21(yz * C - x * sin)
+ ._m02(xz * C - y * sin)
+ ._m12(yz * C + x * sin)
+ ._m22(cos + z * z * C)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4f rotationX(float ang) {
+ float sin = Math.sin(ang), cos = Math.cosFromSin(sin, ang);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m11(cos)._m12(sin)._m21(-sin)._m22(cos)._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4f rotationY(float ang) {
+ float sin = Math.sin(ang), cos = Math.cosFromSin(sin, ang);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(cos)._m02(-sin)._m20(sin)._m22(cos)._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4f rotationZ(float ang) {
+ float sin = Math.sin(ang), cos = Math.cosFromSin(sin, ang);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ return this._m00(cos)._m01(sin)._m10(-sin)._m11(cos)._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis to align the local +X
towards (dirX, dirY)
.
+ *
+ * The vector (dirX, dirY)
must be a unit vector.
+ *
+ * @param dirX
+ * the x component of the normalized direction
+ * @param dirY
+ * the y component of the normalized direction
+ * @return this
+ */
+ public Matrix4f rotationTowardsXY(float dirX, float dirY) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ return this._m00(dirY)._m01(dirX)._m10(-dirX)._m11(dirY)._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f rotationXYZ(float angleX, float angleY, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ float nm01 = -sinX * -sinY, nm02 = cosX * -sinY;
+ return this
+ ._m20(sinY)
+ ._m21(-sinX * cosY)
+ ._m22(cosX * cosY)
+ ._m00(cosY * cosZ)
+ ._m01(nm01 * cosZ + cosX * sinZ)
+ ._m02(nm02 * cosZ + sinX * sinZ)
+ ._m10(cosY * -sinZ)
+ ._m11(nm01 * -sinZ + cosX * cosZ)
+ ._m12(nm02 * -sinZ + sinX * cosZ)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4f rotationZYX(float angleZ, float angleY, float angleX) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float nm20 = cosZ * sinY;
+ float nm21 = sinZ * sinY;
+ return this
+ ._m00(cosZ * cosY)
+ ._m01(sinZ * cosY)
+ ._m02(-sinY)
+ ._m03(0.0f)
+ ._m10(-sinZ * cosX + nm20 * sinX)
+ ._m11(cosZ * cosX + nm21 * sinX)
+ ._m12(cosY * sinX)
+ ._m13(0.0f)
+ ._m20(-sinZ * -sinX + nm20 * cosX)
+ ._m21(cosZ * -sinX + nm21 * cosX)
+ ._m22(cosY * cosX)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f rotationYXZ(float angleY, float angleX, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float nm10 = sinY * sinX, nm12 = cosY * sinX;
+ return this
+ ._m20(sinY * cosX)
+ ._m21(-sinX)
+ ._m22(cosY * cosX)
+ ._m23(0.0f)
+ ._m00(cosY * cosZ + nm10 * sinZ)
+ ._m01(cosX * sinZ)
+ ._m02(-sinY * cosZ + nm12 * sinZ)
+ ._m03(0.0f)
+ ._m10(cosY * -sinZ + nm10 * cosZ)
+ ._m11(cosX * cosZ)
+ ._m12(-sinY * -sinZ + nm12 * cosZ)
+ ._m13(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set only the upper left 3x3 submatrix of this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f setRotationXYZ(float angleX, float angleY, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float nm01 = -sinX * -sinY;
+ float nm02 = cosX * -sinY;
+ return this
+ ._m20(sinY)
+ ._m21(-sinX * cosY)
+ ._m22(cosX * cosY)
+ ._m00(cosY * cosZ)
+ ._m01(nm01 * cosZ + cosX * sinZ)
+ ._m02(nm02 * cosZ + sinX * sinZ)
+ ._m10(cosY * -sinZ)
+ ._m11(nm01 * -sinZ + cosX * cosZ)
+ ._m12(nm02 * -sinZ + sinX * cosZ)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Set only the upper left 3x3 submatrix of this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4f setRotationZYX(float angleZ, float angleY, float angleX) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float nm20 = cosZ * sinY, nm21 = sinZ * sinY;
+ return this
+ ._m00(cosZ * cosY)
+ ._m01(sinZ * cosY)
+ ._m02(-sinY)
+ ._m10(-sinZ * cosX + nm20 * sinX)
+ ._m11(cosZ * cosX + nm21 * sinX)
+ ._m12(cosY * sinX)
+ ._m20(-sinZ * -sinX + nm20 * cosX)
+ ._m21(cosZ * -sinX + nm21 * cosX)
+ ._m22(cosY * cosX)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Set only the upper left 3x3 submatrix of this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f setRotationYXZ(float angleY, float angleX, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float nm10 = sinY * sinX, nm12 = cosY * sinX;
+ return this
+ ._m20(sinY * cosX)
+ ._m21(-sinX)
+ ._m22(cosY * cosX)
+ ._m00(cosY * cosZ + nm10 * sinZ)
+ ._m01(cosX * sinZ)
+ ._m02(-sinY * cosZ + nm12 * sinZ)
+ ._m10(cosY * -sinZ + nm10 * cosZ)
+ ._m11(cosX * cosZ)
+ ._m12(-sinY * -sinZ + nm12 * cosZ)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Set this matrix to the rotation transformation of the given {@link Quaternionfc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaternionfc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4f rotation(Quaternionfc quat) {
+ float w2 = quat.w() * quat.w();
+ float x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y();
+ float z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw;
+ float xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz;
+ float yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz;
+ float xw = quat.x() * quat.w(), dxw = xw + xw;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ return this
+ ._m00(w2 + x2 - z2 - y2)
+ ._m01(dxy + dzw)
+ ._m02(dxz - dyw)
+ ._m10(-dzw + dxy)
+ ._m11(y2 - z2 + w2 - x2)
+ ._m12(dyz + dxw)
+ ._m20(dyw + dxz)
+ ._m21(dyz - dxw)
+ ._m22(z2 - y2 - x2 + w2)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(float, float, float)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @return this
+ */
+ public Matrix4f translationRotateScale(float tx, float ty, float tz,
+ float qx, float qy, float qz, float qw,
+ float sx, float sy, float sz) {
+ float dqx = qx + qx;
+ float dqy = qy + qy;
+ float dqz = qz + qz;
+ float q00 = dqx * qx;
+ float q11 = dqy * qy;
+ float q22 = dqz * qz;
+ float q01 = dqx * qy;
+ float q02 = dqx * qz;
+ float q03 = dqx * qw;
+ float q12 = dqy * qz;
+ float q13 = dqy * qw;
+ float q23 = dqz * qw;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return this
+ ._m00(sx - (q11 + q22) * sx)
+ ._m01((q01 + q23) * sx)
+ ._m02((q02 - q13) * sx)
+ ._m03(0.0f)
+ ._m10((q01 - q23) * sy)
+ ._m11(sy - (q22 + q00) * sy)
+ ._m12((q12 + q03) * sy)
+ ._m13(0.0f)
+ ._m20((q02 + q13) * sz)
+ ._m21((q12 - q03) * sz)
+ ._m22(sz - (q11 + q00) * sz)
+ ._m23(0.0f)
+ ._m30(tx)
+ ._m31(ty)
+ ._m32(tz)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | (one ? PROPERTY_ORTHONORMAL : 0));
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(Vector3fc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4f translationRotateScale(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(scale)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(float)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param scale
+ * the scaling factor for all three axes
+ * @return this
+ */
+ public Matrix4f translationRotateScale(float tx, float ty, float tz,
+ float qx, float qy, float qz, float qw,
+ float scale) {
+ return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(float)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4f translationRotateScale(Vector3fc translation,
+ Quaternionfc quat,
+ float scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(float, float, float, float, float, float, float, float, float, float)
+ * @see #invert()
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @return this
+ */
+ public Matrix4f translationRotateScaleInvert(float tx, float ty, float tz,
+ float qx, float qy, float qz, float qw,
+ float sx, float sy, float sz) {
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ if (one)
+ return translationRotateScale(tx, ty, tz, qx, qy, qz, qw, sx, sy, sz).invertOrthonormal(this);
+ float nqx = -qx, nqy = -qy, nqz = -qz;
+ float dqx = nqx + nqx;
+ float dqy = nqy + nqy;
+ float dqz = nqz + nqz;
+ float q00 = dqx * nqx;
+ float q11 = dqy * nqy;
+ float q22 = dqz * nqz;
+ float q01 = dqx * nqy;
+ float q02 = dqx * nqz;
+ float q03 = dqx * qw;
+ float q12 = dqy * nqz;
+ float q13 = dqy * qw;
+ float q23 = dqz * qw;
+ float isx = 1/sx, isy = 1/sy, isz = 1/sz;
+ return this
+ ._m00(isx * (1.0f - q11 - q22))
+ ._m01(isy * (q01 + q23))
+ ._m02(isz * (q02 - q13))
+ ._m03(0.0f)
+ ._m10(isx * (q01 - q23))
+ ._m11(isy * (1.0f - q22 - q00))
+ ._m12(isz * (q12 + q03))
+ ._m13(0.0f)
+ ._m20(isx * (q02 + q13))
+ ._m21(isy * (q12 - q03))
+ ._m22(isz * (1.0f - q11 - q00))
+ ._m23(0.0f)
+ ._m30(-m00 * tx - m10 * ty - m20 * tz)
+ ._m31(-m01 * tx - m11 * ty - m21 * tz)
+ ._m32(-m02 * tx - m12 * ty - m22 * tz)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE);
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(Vector3fc, Quaternionfc, Vector3fc)
+ * @see #invert()
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4f translationRotateScaleInvert(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale) {
+ return translationRotateScaleInvert(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to (T * R * S)-1
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales all three axes by scale
.
+ *
+ * This method is equivalent to calling: translationRotateScale(...).invert()
+ *
+ * @see #translationRotateScale(Vector3fc, Quaternionfc, float)
+ * @see #invert()
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4f translationRotateScaleInvert(Vector3fc translation,
+ Quaternionfc quat,
+ float scale) {
+ return translationRotateScaleInvert(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale, scale, scale);
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation - and possibly scaling - transformation specified by the quaternion (qx, qy, qz, qw)
, S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
and M
is an {@link #isAffine() affine} matrix.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mulAffine(m)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(float, float, float)
+ * @see #mulAffine(Matrix4fc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @param m
+ * the {@link #isAffine() affine} matrix to multiply by
+ * @return this
+ */
+ public Matrix4f translationRotateScaleMulAffine(float tx, float ty, float tz,
+ float qx, float qy, float qz, float qw,
+ float sx, float sy, float sz,
+ Matrix4f m) {
+ float w2 = qw * qw;
+ float x2 = qx * qx;
+ float y2 = qy * qy;
+ float z2 = qz * qz;
+ float zw = qz * qw;
+ float xy = qx * qy;
+ float xz = qx * qz;
+ float yw = qy * qw;
+ float yz = qy * qz;
+ float xw = qx * qw;
+ float nm00 = w2 + x2 - z2 - y2;
+ float nm01 = xy + zw + zw + xy;
+ float nm02 = xz - yw + xz - yw;
+ float nm10 = -zw + xy - zw + xy;
+ float nm11 = y2 - z2 + w2 - x2;
+ float nm12 = yz + yz + xw + xw;
+ float nm20 = yw + xz + xz + yw;
+ float nm21 = yz + yz - xw - xw;
+ float nm22 = z2 - y2 - x2 + w2;
+ float m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02;
+ float m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02;
+ this._m02(nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02)
+ ._m00(m00)
+ ._m01(m01)
+ ._m03(0.0f);
+ float m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12;
+ float m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12;
+ this._m12(nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12)
+ ._m10(m10)
+ ._m11(m11)
+ ._m13(0.0f);
+ float m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22;
+ float m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22;
+ this._m22(nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22)
+ ._m20(m20)
+ ._m21(m21)
+ ._m23(0.0f);
+ float m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx;
+ float m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty;
+ this._m32(nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz)
+ ._m30(m30)
+ ._m31(m31)
+ ._m33(1.0f);
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return _properties(PROPERTY_AFFINE | (one && (m.properties & PROPERTY_ORTHONORMAL) != 0 ? PROPERTY_ORTHONORMAL : 0));
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is the given translation
,
+ * R
is a rotation - and possibly scaling - transformation specified by the given quaternion, S
is a scaling transformation
+ * which scales the axes by scale
and M
is an {@link #isAffine() affine} matrix.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale).mulAffine(m)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ * @see #mulAffine(Matrix4fc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @param m
+ * the {@link #isAffine() affine} matrix to multiply by
+ * @return this
+ */
+ public Matrix4f translationRotateScaleMulAffine(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale,
+ Matrix4f m) {
+ return translationRotateScaleMulAffine(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z(), m);
+ }
+
+ /**
+ * Set this
matrix to T * R
, where T
is a translation by the given (tx, ty, tz)
and
+ * R
is a rotation - and possibly scaling - transformation specified by the quaternion (qx, qy, qz, qw)
.
+ *
+ * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @return this
+ */
+ public Matrix4f translationRotate(float tx, float ty, float tz, float qx, float qy, float qz, float qw) {
+ float w2 = qw * qw;
+ float x2 = qx * qx;
+ float y2 = qy * qy;
+ float z2 = qz * qz;
+ float zw = qz * qw;
+ float xy = qx * qy;
+ float xz = qx * qz;
+ float yw = qy * qw;
+ float yz = qy * qz;
+ float xw = qx * qw;
+ return this
+ ._m00(w2 + x2 - z2 - y2)
+ ._m01(xy + zw + zw + xy)
+ ._m02(xz - yw + xz - yw)
+ ._m10(-zw + xy - zw + xy)
+ ._m11(y2 - z2 + w2 - x2)
+ ._m12(yz + yz + xw + xw)
+ ._m20(yw + xz + xz + yw)
+ ._m21(yz + yz - xw - xw)
+ ._m22(z2 - y2 - x2 + w2)
+ ._m30(tx)
+ ._m31(ty)
+ ._m32(tz)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Set this
matrix to T * R
, where T
is a translation by the given (tx, ty, tz)
and
+ * R
is a rotation - and possibly scaling - transformation specified by the given quaternion.
+ *
+ * When transforming a vector by the resulting matrix the rotation - and possibly scaling - transformation will be applied first and then the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param quat
+ * the quaternion representing a rotation
+ * @return this
+ */
+ public Matrix4f translationRotate(float tx, float ty, float tz, Quaternionfc quat) {
+ return translationRotate(tx, ty, tz, quat.x(), quat.y(), quat.z(), quat.w());
+ }
+
+ /**
+ * Set the upper left 3x3 submatrix of this {@link Matrix4f} to the given {@link Matrix3fc} and don't change the other elements.
+ *
+ * @param mat
+ * the 3x3 matrix
+ * @return this
+ */
+ public Matrix4f set3x3(Matrix3fc mat) {
+ return
+ set3x3Matrix3fc(mat).
+ _properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+ private Matrix4f set3x3Matrix3fc(Matrix3fc mat) {
+ return this
+ ._m00(mat.m00())
+ ._m01(mat.m01())
+ ._m02(mat.m02())
+ ._m10(mat.m10())
+ ._m11(mat.m11())
+ ._m12(mat.m12())
+ ._m20(mat.m20())
+ ._m21(mat.m21())
+ ._m22(mat.m22());
+ }
+
+ public Vector4f transform(Vector4f v) {
+ return v.mul(this);
+ }
+
+ public Vector4f transform(Vector4fc v, Vector4f dest) {
+ return v.mul(this, dest);
+ }
+
+ public Vector4f transform(float x, float y, float z, float w, Vector4f dest) {
+ return dest.set(x, y, z, w).mul(this);
+ }
+
+ public Vector4f transformTranspose(Vector4f v) {
+ return v.mulTranspose(this);
+ }
+ public Vector4f transformTranspose(Vector4fc v, Vector4f dest) {
+ return v.mulTranspose(this, dest);
+ }
+ public Vector4f transformTranspose(float x, float y, float z, float w, Vector4f dest) {
+ return dest.set(x, y, z, w).mulTranspose(this);
+ }
+
+ public Vector4f transformProject(Vector4f v) {
+ return v.mulProject(this);
+ }
+
+ public Vector4f transformProject(Vector4fc v, Vector4f dest) {
+ return v.mulProject(this, dest);
+ }
+
+ public Vector4f transformProject(float x, float y, float z, float w, Vector4f dest) {
+ return dest.set(x, y, z, w).mulProject(this);
+ }
+
+ public Vector3f transformProject(Vector4fc v, Vector3f dest) {
+ return v.mulProject(this, dest);
+ }
+
+ public Vector3f transformProject(float x, float y, float z, float w, Vector3f dest) {
+ return dest.set(x, y, z).mulProject(this, w, dest);
+ }
+
+ public Vector3f transformProject(Vector3f v) {
+ return v.mulProject(this);
+ }
+
+ public Vector3f transformProject(Vector3fc v, Vector3f dest) {
+ return v.mulProject(this, dest);
+ }
+
+ public Vector3f transformProject(float x, float y, float z, Vector3f dest) {
+ return dest.set(x, y, z).mulProject(this);
+ }
+
+ public Vector3f transformPosition(Vector3f v) {
+ return v.mulPosition(this);
+ }
+
+ public Vector3f transformPosition(Vector3fc v, Vector3f dest) {
+ return transformPosition(v.x(), v.y(), v.z(), dest);
+ }
+
+ public Vector3f transformPosition(float x, float y, float z, Vector3f dest) {
+ return dest.set(x, y, z).mulPosition(this);
+ }
+
+ public Vector3f transformDirection(Vector3f v) {
+ return transformDirection(v.x, v.y, v.z, v);
+ }
+
+ public Vector3f transformDirection(Vector3fc v, Vector3f dest) {
+ return transformDirection(v.x(), v.y(), v.z(), dest);
+ }
+
+ public Vector3f transformDirection(float x, float y, float z, Vector3f dest) {
+ return dest.set(x, y, z).mulDirection(this);
+ }
+
+ public Vector4f transformAffine(Vector4f v) {
+ return v.mulAffine(this, v);
+ }
+
+ public Vector4f transformAffine(Vector4fc v, Vector4f dest) {
+ return transformAffine(v.x(), v.y(), v.z(), v.w(), dest);
+ }
+
+ public Vector4f transformAffine(float x, float y, float z, float w, Vector4f dest) {
+ return dest.set(x, y, z, w).mulAffine(this, dest);
+ }
+
+ public Matrix4f scale(Vector3fc xyz, Matrix4f dest) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @return this
+ */
+ public Matrix4f scale(Vector3fc xyz) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), this);
+ }
+
+ public Matrix4f scale(float xyz, Matrix4f dest) {
+ return scale(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * Individual scaling of all three axes can be applied using {@link #scale(float, float, float)}.
+ *
+ * @see #scale(float, float, float)
+ *
+ * @param xyz
+ * the factor for all components
+ * @return this
+ */
+ public Matrix4f scale(float xyz) {
+ return scale(xyz, xyz, xyz);
+ }
+
+ public Matrix4f scaleXY(float x, float y, Matrix4f dest) {
+ return scale(x, y, 1.0f, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the X axis by x
and the Y axis by y
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix4f scaleXY(float x, float y) {
+ return scale(x, y, 1.0f);
+ }
+
+ public Matrix4f scale(float x, float y, float z, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ return scaleGeneric(x, y, z, dest);
+ }
+ private Matrix4f scaleGeneric(float x, float y, float z, Matrix4f dest) {
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ return dest
+ ._m00(m00 * x)
+ ._m01(m01 * x)
+ ._m02(m02 * x)
+ ._m03(m03 * x)
+ ._m10(m10 * y)
+ ._m11(m11 * y)
+ ._m12(m12 * y)
+ ._m13(m13 * y)
+ ._m20(m20 * z)
+ ._m21(m21 * z)
+ ._m22(m22 * z)
+ ._m23(m23 * z)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4f scale(float x, float y, float z) {
+ return scale(x, y, z, this);
+ }
+
+ public Matrix4f scaleAround(float sx, float sy, float sz, float ox, float oy, float oz, Matrix4f dest) {
+ float nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ float nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ float nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ float nm33 = m03 * ox + m13 * oy + m23 * oz + m33;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return dest
+ ._m00(m00 * sx)
+ ._m01(m01 * sx)
+ ._m02(m02 * sx)
+ ._m03(m03 * sx)
+ ._m10(m10 * sy)
+ ._m11(m11 * sy)
+ ._m12(m12 * sy)
+ ._m13(m13 * sy)
+ ._m20(m20 * sz)
+ ._m21(m21 * sz)
+ ._m22(m22 * sz)
+ ._m23(m23 * sz)
+ ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30)
+ ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31)
+ ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32)
+ ._m33(-dest.m03 * ox - dest.m13 * oy - dest.m23 * oz + nm33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4f scaleAround(float sx, float sy, float sz, float ox, float oy, float oz) {
+ return scaleAround(sx, sy, sz, ox, oy, oz, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4f scaleAround(float factor, float ox, float oy, float oz) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, this);
+ }
+
+ public Matrix4f scaleAround(float factor, float ox, float oy, float oz, Matrix4f dest) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, dest);
+ }
+
+ public Matrix4f scaleLocal(float x, float y, float z, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ return scaleLocalGeneric(x, y, z, dest);
+ }
+ private Matrix4f scaleLocalGeneric(float x, float y, float z, Matrix4f dest) {
+ float nm00 = x * m00;
+ float nm01 = y * m01;
+ float nm02 = z * m02;
+ float nm10 = x * m10;
+ float nm11 = y * m11;
+ float nm12 = z * m12;
+ float nm20 = x * m20;
+ float nm21 = y * m21;
+ float nm22 = z * m22;
+ float nm30 = x * m30;
+ float nm31 = y * m31;
+ float nm32 = z * m32;
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ public Matrix4f scaleLocal(float xyz, Matrix4f dest) {
+ return scaleLocal(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given xyz factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param xyz
+ * the factor of the x, y and z component
+ * @return this
+ */
+ public Matrix4f scaleLocal(float xyz) {
+ return scaleLocal(xyz, this);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4f scaleLocal(float x, float y, float z) {
+ return scaleLocal(x, y, z, this);
+ }
+
+ public Matrix4f scaleAroundLocal(float sx, float sy, float sz, float ox, float oy, float oz, Matrix4f dest) {
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return dest
+ ._m00(sx * (m00 - ox * m03) + ox * m03)
+ ._m01(sy * (m01 - oy * m03) + oy * m03)
+ ._m02(sz * (m02 - oz * m03) + oz * m03)
+ ._m03(m03)
+ ._m10(sx * (m10 - ox * m13) + ox * m13)
+ ._m11(sy * (m11 - oy * m13) + oy * m13)
+ ._m12(sz * (m12 - oz * m13) + oz * m13)
+ ._m13(m13)
+ ._m20(sx * (m20 - ox * m23) + ox * m23)
+ ._m21(sy * (m21 - oy * m23) + oy * m23)
+ ._m22(sz * (m22 - oz * m23) + oz * m23)
+ ._m23(m23)
+ ._m30(sx * (m30 - ox * m33) + ox * m33)
+ ._m31(sy * (m31 - oy * m33) + oy * m33)
+ ._m32(sz * (m32 - oz * m33) + oz * m33)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4f().translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz).mul(this, this)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4f scaleAroundLocal(float sx, float sy, float sz, float ox, float oy, float oz) {
+ return scaleAroundLocal(sx, sy, sz, ox, oy, oz, this);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4f().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, this)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4f scaleAroundLocal(float factor, float ox, float oy, float oz) {
+ return scaleAroundLocal(factor, factor, factor, ox, oy, oz, this);
+ }
+
+ public Matrix4f scaleAroundLocal(float factor, float ox, float oy, float oz, Matrix4f dest) {
+ return scaleAroundLocal(factor, factor, factor, ox, oy, oz, dest);
+ }
+
+ public Matrix4f rotateX(float ang, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationX(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float x = m30, y = m31, z = m32;
+ return dest.rotationX(ang).setTranslation(x, y, z);
+ }
+ return rotateXInternal(ang, dest);
+ }
+ private Matrix4f rotateXInternal(float ang, Matrix4f dest) {
+ float sin = Math.sin(ang), cos = Math.cosFromSin(sin, ang);
+ float lm10 = m10, lm11 = m11, lm12 = m12, lm13 = m13, lm20 = m20, lm21 = m21, lm22 = m22, lm23 = m23;
+ return dest
+ ._m20(Math.fma(lm10, -sin, lm20 * cos))
+ ._m21(Math.fma(lm11, -sin, lm21 * cos))
+ ._m22(Math.fma(lm12, -sin, lm22 * cos))
+ ._m23(Math.fma(lm13, -sin, lm23 * cos))
+ ._m10(Math.fma(lm10, cos, lm20 * sin))
+ ._m11(Math.fma(lm11, cos, lm21 * sin))
+ ._m12(Math.fma(lm12, cos, lm22 * sin))
+ ._m13(Math.fma(lm13, cos, lm23 * sin))
+ ._m00(m00)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4f rotateX(float ang) {
+ return rotateX(ang, this);
+ }
+
+ public Matrix4f rotateY(float ang, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationY(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float x = m30, y = m31, z = m32;
+ return dest.rotationY(ang).setTranslation(x, y, z);
+ }
+ return rotateYInternal(ang, dest);
+ }
+ private Matrix4f rotateYInternal(float ang, Matrix4f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ // add temporaries for dependent values
+ float nm00 = Math.fma(m00, cos, m20 * -sin);
+ float nm01 = Math.fma(m01, cos, m21 * -sin);
+ float nm02 = Math.fma(m02, cos, m22 * -sin);
+ float nm03 = Math.fma(m03, cos, m23 * -sin);
+ // set non-dependent values directly
+ return dest
+ ._m20(Math.fma(m00, sin, m20 * cos))
+ ._m21(Math.fma(m01, sin, m21 * cos))
+ ._m22(Math.fma(m02, sin, m22 * cos))
+ ._m23(Math.fma(m03, sin, m23 * cos))
+ // set other values
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(m10)
+ ._m11(m11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4f rotateY(float ang) {
+ return rotateY(ang, this);
+ }
+
+ public Matrix4f rotateZ(float ang, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZ(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float x = m30, y = m31, z = m32;
+ return dest.rotationZ(ang).setTranslation(x, y, z);
+ }
+ return rotateZInternal(ang, dest);
+ }
+ private Matrix4f rotateZInternal(float ang, Matrix4f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ return rotateTowardsXY(sin, cos, dest);
+ }
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4f rotateZ(float ang) {
+ return rotateZ(ang, this);
+ }
+
+ /**
+ * Apply rotation about the Z axis to align the local +X
towards (dirX, dirY)
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * The vector (dirX, dirY)
must be a unit vector.
+ *
+ * @param dirX
+ * the x component of the normalized direction
+ * @param dirY
+ * the y component of the normalized direction
+ * @return this
+ */
+ public Matrix4f rotateTowardsXY(float dirX, float dirY) {
+ return rotateTowardsXY(dirX, dirY, this);
+ }
+
+ public Matrix4f rotateTowardsXY(float dirX, float dirY, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationTowardsXY(dirX, dirY);
+ float nm00 = Math.fma(m00, dirY, m10 * dirX);
+ float nm01 = Math.fma(m01, dirY, m11 * dirX);
+ float nm02 = Math.fma(m02, dirY, m12 * dirX);
+ float nm03 = Math.fma(m03, dirY, m13 * dirX);
+ return dest
+ ._m10(Math.fma(m00, -dirX, m10 * dirY))
+ ._m11(Math.fma(m01, -dirX, m11 * dirY))
+ ._m12(Math.fma(m02, -dirX, m12 * dirY))
+ ._m13(Math.fma(m03, -dirX, m13 * dirY))
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation of angles.x
radians about the X axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angles.x()).rotateY(angles.y()).rotateZ(angles.z())
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4f rotateXYZ(Vector3fc angles) {
+ return rotateXYZ(angles.x(), angles.y(), angles.z());
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f rotateXYZ(float angleX, float angleY, float angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix4f rotateXYZ(float angleX, float angleY, float angleZ, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationXYZ(angleX, angleY, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
+ } else if ((properties & PROPERTY_AFFINE) != 0)
+ return dest.rotateAffineXYZ(angleX, angleY, angleZ);
+ return rotateXYZInternal(angleX, angleY, angleZ, dest);
+ }
+ private Matrix4f rotateXYZInternal(float angleX, float angleY, float angleZ, Matrix4f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm10 = Math.fma(m10, cosX, m20 * sinX);
+ float nm11 = Math.fma(m11, cosX, m21 * sinX);
+ float nm12 = Math.fma(m12, cosX, m22 * sinX);
+ float nm13 = Math.fma(m13, cosX, m23 * sinX);
+ float nm20 = Math.fma(m10, m_sinX, m20 * cosX);
+ float nm21 = Math.fma(m11, m_sinX, m21 * cosX);
+ float nm22 = Math.fma(m12, m_sinX, m22 * cosX);
+ float nm23 = Math.fma(m13, m_sinX, m23 * cosX);
+ // rotateY
+ float nm00 = Math.fma(m00, cosY, nm20 * m_sinY);
+ float nm01 = Math.fma(m01, cosY, nm21 * m_sinY);
+ float nm02 = Math.fma(m02, cosY, nm22 * m_sinY);
+ float nm03 = Math.fma(m03, cosY, nm23 * m_sinY);
+ return dest
+ ._m20(Math.fma(m00, sinY, nm20 * cosY))
+ ._m21(Math.fma(m01, sinY, nm21 * cosY))
+ ._m22(Math.fma(m02, sinY, nm22 * cosY))
+ ._m23(Math.fma(m03, sinY, nm23 * cosY))
+ // rotateZ
+ ._m00(Math.fma(nm00, cosZ, nm10 * sinZ))
+ ._m01(Math.fma(nm01, cosZ, nm11 * sinZ))
+ ._m02(Math.fma(nm02, cosZ, nm12 * sinZ))
+ ._m03(Math.fma(nm03, cosZ, nm13 * sinZ))
+ ._m10(Math.fma(nm00, m_sinZ, nm10 * cosZ))
+ ._m11(Math.fma(nm01, m_sinZ, nm11 * cosZ))
+ ._m12(Math.fma(nm02, m_sinZ, nm12 * cosZ))
+ ._m13(Math.fma(nm03, m_sinZ, nm13 * cosZ))
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f rotateAffineXYZ(float angleX, float angleY, float angleZ) {
+ return rotateAffineXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix4f rotateAffineXYZ(float angleX, float angleY, float angleZ, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationXYZ(angleX, angleY, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
+ }
+ return rotateAffineXYZInternal(angleX, angleY, angleZ, dest);
+ }
+ private Matrix4f rotateAffineXYZInternal(float angleX, float angleY, float angleZ, Matrix4f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm10 = Math.fma(m10, cosX, m20 * sinX);
+ float nm11 = Math.fma(m11, cosX, m21 * sinX);
+ float nm12 = Math.fma(m12, cosX, m22 * sinX);
+ float nm20 = Math.fma(m10, m_sinX, m20 * cosX);
+ float nm21 = Math.fma(m11, m_sinX, m21 * cosX);
+ float nm22 = Math.fma(m12, m_sinX, m22 * cosX);
+ // rotateY
+ float nm00 = Math.fma(m00, cosY, nm20 * m_sinY);
+ float nm01 = Math.fma(m01, cosY, nm21 * m_sinY);
+ float nm02 = Math.fma(m02, cosY, nm22 * m_sinY);
+ return dest
+ ._m20(Math.fma(m00, sinY, nm20 * cosY))
+ ._m21(Math.fma(m01, sinY, nm21 * cosY))
+ ._m22(Math.fma(m02, sinY, nm22 * cosY))
+ ._m23(0.0f)
+ // rotateZ
+ ._m00(Math.fma(nm00, cosZ, nm10 * sinZ))
+ ._m01(Math.fma(nm01, cosZ, nm11 * sinZ))
+ ._m02(Math.fma(nm02, cosZ, nm12 * sinZ))
+ ._m03(0.0f)
+ ._m10(Math.fma(nm00, m_sinZ, nm10 * cosZ))
+ ._m11(Math.fma(nm01, m_sinZ, nm11 * cosZ))
+ ._m12(Math.fma(nm02, m_sinZ, nm12 * cosZ))
+ ._m13(0.0f)
+ // copy last column from 'this'
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation of angles.z
radians about the Z axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.x
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4f rotateZYX(Vector3f angles) {
+ return rotateZYX(angles.z, angles.y, angles.x);
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4f rotateZYX(float angleZ, float angleY, float angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix4f rotateZYX(float angleZ, float angleY, float angleX, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZYX(angleZ, angleY, angleX);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz);
+ } else if ((properties & PROPERTY_AFFINE) != 0)
+ return dest.rotateAffineZYX(angleZ, angleY, angleX);
+ return rotateZYXInternal(angleZ, angleY, angleX, dest);
+ }
+ private Matrix4f rotateZYXInternal(float angleZ, float angleY, float angleX, Matrix4f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = m00 * cosZ + m10 * sinZ;
+ float nm01 = m01 * cosZ + m11 * sinZ;
+ float nm02 = m02 * cosZ + m12 * sinZ;
+ float nm03 = m03 * cosZ + m13 * sinZ;
+ float nm10 = m00 * m_sinZ + m10 * cosZ;
+ float nm11 = m01 * m_sinZ + m11 * cosZ;
+ float nm12 = m02 * m_sinZ + m12 * cosZ;
+ float nm13 = m03 * m_sinZ + m13 * cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY + m20 * cosY;
+ float nm21 = nm01 * sinY + m21 * cosY;
+ float nm22 = nm02 * sinY + m22 * cosY;
+ float nm23 = nm03 * sinY + m23 * cosY;
+ return dest
+ ._m00(nm00 * cosY + m20 * m_sinY)
+ ._m01(nm01 * cosY + m21 * m_sinY)
+ ._m02(nm02 * cosY + m22 * m_sinY)
+ ._m03(nm03 * cosY + m23 * m_sinY)
+ ._m10(nm10 * cosX + nm20 * sinX)
+ ._m11(nm11 * cosX + nm21 * sinX)
+ ._m12(nm12 * cosX + nm22 * sinX)
+ ._m13(nm13 * cosX + nm23 * sinX)
+ ._m20(nm10 * m_sinX + nm20 * cosX)
+ ._m21(nm11 * m_sinX + nm21 * cosX)
+ ._m22(nm12 * m_sinX + nm22 * cosX)
+ ._m23(nm13 * m_sinX + nm23 * cosX)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4f rotateAffineZYX(float angleZ, float angleY, float angleX) {
+ return rotateAffineZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix4f rotateAffineZYX(float angleZ, float angleY, float angleX, Matrix4f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = m00 * cosZ + m10 * sinZ;
+ float nm01 = m01 * cosZ + m11 * sinZ;
+ float nm02 = m02 * cosZ + m12 * sinZ;
+ float nm10 = m00 * m_sinZ + m10 * cosZ;
+ float nm11 = m01 * m_sinZ + m11 * cosZ;
+ float nm12 = m02 * m_sinZ + m12 * cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY + m20 * cosY;
+ float nm21 = nm01 * sinY + m21 * cosY;
+ float nm22 = nm02 * sinY + m22 * cosY;
+ return dest
+ ._m00(nm00 * cosY + m20 * m_sinY)
+ ._m01(nm01 * cosY + m21 * m_sinY)
+ ._m02(nm02 * cosY + m22 * m_sinY)
+ ._m03(0.0f)
+ ._m10(nm10 * cosX + nm20 * sinX)
+ ._m11(nm11 * cosX + nm21 * sinX)
+ ._m12(nm12 * cosX + nm22 * sinX)
+ ._m13(0.0f)
+ ._m20(nm10 * m_sinX + nm20 * cosX)
+ ._m21(nm11 * m_sinX + nm21 * cosX)
+ ._m22(nm12 * m_sinX + nm22 * cosX)
+ ._m23(0.0f)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation of angles.y
radians about the Y axis, followed by a rotation of angles.x
radians about the X axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4f rotateYXZ(Vector3f angles) {
+ return rotateYXZ(angles.y, angles.x, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f rotateYXZ(float angleY, float angleX, float angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix4f rotateYXZ(float angleY, float angleX, float angleZ, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationYXZ(angleY, angleX, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz);
+ } else if ((properties & PROPERTY_AFFINE) != 0)
+ return dest.rotateAffineYXZ(angleY, angleX, angleZ);
+ return rotateYXZInternal(angleY, angleX, angleZ, dest);
+ }
+ private Matrix4f rotateYXZInternal(float angleY, float angleX, float angleZ, Matrix4f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm20 = m00 * sinY + m20 * cosY;
+ float nm21 = m01 * sinY + m21 * cosY;
+ float nm22 = m02 * sinY + m22 * cosY;
+ float nm23 = m03 * sinY + m23 * cosY;
+ float nm00 = m00 * cosY + m20 * m_sinY;
+ float nm01 = m01 * cosY + m21 * m_sinY;
+ float nm02 = m02 * cosY + m22 * m_sinY;
+ float nm03 = m03 * cosY + m23 * m_sinY;
+ // rotateX
+ float nm10 = m10 * cosX + nm20 * sinX;
+ float nm11 = m11 * cosX + nm21 * sinX;
+ float nm12 = m12 * cosX + nm22 * sinX;
+ float nm13 = m13 * cosX + nm23 * sinX;
+ return dest
+ ._m20(m10 * m_sinX + nm20 * cosX)
+ ._m21(m11 * m_sinX + nm21 * cosX)
+ ._m22(m12 * m_sinX + nm22 * cosX)
+ ._m23(m13 * m_sinX + nm23 * cosX)
+ ._m00(nm00 * cosZ + nm10 * sinZ)
+ ._m01(nm01 * cosZ + nm11 * sinZ)
+ ._m02(nm02 * cosZ + nm12 * sinZ)
+ ._m03(nm03 * cosZ + nm13 * sinZ)
+ ._m10(nm00 * m_sinZ + nm10 * cosZ)
+ ._m11(nm01 * m_sinZ + nm11 * cosZ)
+ ._m12(nm02 * m_sinZ + nm12 * cosZ)
+ ._m13(nm03 * m_sinZ + nm13 * cosZ)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4f rotateAffineYXZ(float angleY, float angleX, float angleZ) {
+ return rotateAffineYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix4f rotateAffineYXZ(float angleY, float angleX, float angleZ, Matrix4f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm20 = m00 * sinY + m20 * cosY;
+ float nm21 = m01 * sinY + m21 * cosY;
+ float nm22 = m02 * sinY + m22 * cosY;
+ float nm00 = m00 * cosY + m20 * m_sinY;
+ float nm01 = m01 * cosY + m21 * m_sinY;
+ float nm02 = m02 * cosY + m22 * m_sinY;
+ // rotateX
+ float nm10 = m10 * cosX + nm20 * sinX;
+ float nm11 = m11 * cosX + nm21 * sinX;
+ float nm12 = m12 * cosX + nm22 * sinX;
+ return dest
+ ._m20(m10 * m_sinX + nm20 * cosX)
+ ._m21(m11 * m_sinX + nm21 * cosX)
+ ._m22(m12 * m_sinX + nm22 * cosX)
+ ._m23(0.0f)
+ ._m00(nm00 * cosZ + nm10 * sinZ)
+ ._m01(nm01 * cosZ + nm11 * sinZ)
+ ._m02(nm02 * cosZ + nm12 * sinZ)
+ ._m03(0.0f)
+ ._m10(nm00 * m_sinZ + nm10 * cosZ)
+ ._m11(nm01 * m_sinZ + nm11 * cosZ)
+ ._m12(nm02 * m_sinZ + nm12 * cosZ)
+ ._m13(0.0f)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotate(float ang, float x, float y, float z, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(ang, x, y, z);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(ang, x, y, z, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAffine(ang, x, y, z, dest);
+ return rotateGeneric(ang, x, y, z, dest);
+ }
+ private Matrix4f rotateGeneric(float ang, float x, float y, float z, Matrix4f dest) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateX(x * ang, dest);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateY(y * ang, dest);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateZ(z * ang, dest);
+ return rotateGenericInternal(ang, x, y, z, dest);
+ }
+ private Matrix4f rotateGenericInternal(float ang, float x, float y, float z, Matrix4f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float rm00 = xx * C + c;
+ float rm01 = xy * C + z * s;
+ float rm02 = xz * C - y * s;
+ float rm10 = xy * C - z * s;
+ float rm11 = yy * C + c;
+ float rm12 = yz * C + x * s;
+ float rm20 = xz * C + y * s;
+ float rm21 = yz * C - x * s;
+ float rm22 = zz * C + c;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ float nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ return dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4f rotate(float ang, float x, float y, float z) {
+ return rotate(ang, x, y, z, this);
+ }
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateTranslation(float ang, float x, float y, float z, Matrix4f dest) {
+ float tx = m30, ty = m31, tz = m32;
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return dest.rotationX(x * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return dest.rotationY(y * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return dest.rotationZ(z * ang).setTranslation(tx, ty, tz);
+ return rotateTranslationInternal(ang, x, y, z, dest);
+ }
+ private Matrix4f rotateTranslationInternal(float ang, float x, float y, float z, Matrix4f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float rm00 = xx * C + c;
+ float rm01 = xy * C + z * s;
+ float rm02 = xz * C - y * s;
+ float rm10 = xy * C - z * s;
+ float rm11 = yy * C + c;
+ float rm12 = yz * C + x * s;
+ float rm20 = xz * C + y * s;
+ float rm21 = yz * C - x * s;
+ float rm22 = zz * C + c;
+ return dest
+ ._m20(rm20)
+ ._m21(rm21)
+ ._m22(rm22)
+ ._m00(rm00)
+ ._m01(rm01)
+ ._m02(rm02)
+ ._m03(0.0f)
+ ._m10(rm10)
+ ._m11(rm11)
+ ._m12(rm12)
+ ._m13(0.0f)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(1.0f)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateAffine(float ang, float x, float y, float z, Matrix4f dest) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateX(x * ang, dest);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateY(y * ang, dest);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateZ(z * ang, dest);
+ return rotateAffineInternal(ang, x, y, z, dest);
+ }
+ private Matrix4f rotateAffineInternal(float ang, float x, float y, float z, Matrix4f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float rm00 = xx * C + c;
+ float rm01 = xy * C + z * s;
+ float rm02 = xz * C - y * s;
+ float rm10 = xy * C - z * s;
+ float rm11 = yy * C + c;
+ float rm12 = yz * C + x * s;
+ float rm20 = xz * C + y * s;
+ float rm21 = yz * C - x * s;
+ float rm22 = zz * C + c;
+ // add temporaries for dependent values
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ return dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0f)
+ // set other values
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(1.0f)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4f rotateAffine(float ang, float x, float y, float z) {
+ return rotateAffine(ang, x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateLocal(float ang, float x, float y, float z, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(ang, x, y, z);
+ return rotateLocalGeneric(ang, x, y, z, dest);
+ }
+ private Matrix4f rotateLocalGeneric(float ang, float x, float y, float z, Matrix4f dest) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateLocalX(x * ang, dest);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateLocalY(y * ang, dest);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateLocalZ(z * ang, dest);
+ return rotateLocalGenericInternal(ang, x, y, z, dest);
+ }
+ private Matrix4f rotateLocalGenericInternal(float ang, float x, float y, float z, Matrix4f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float lm00 = xx * C + c;
+ float lm01 = xy * C + z * s;
+ float lm02 = xz * C - y * s;
+ float lm10 = xy * C - z * s;
+ float lm11 = yy * C + c;
+ float lm12 = yz * C + x * s;
+ float lm20 = xz * C + y * s;
+ float lm21 = yz * C - x * s;
+ float lm22 = zz * C + c;
+ float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ float nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ float nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ float nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4f rotateLocal(float ang, float x, float y, float z) {
+ return rotateLocal(ang, x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(float) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateLocalX(float ang, Matrix4f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm02 = sin * m01 + cos * m02;
+ float nm12 = sin * m11 + cos * m12;
+ float nm22 = sin * m21 + cos * m22;
+ float nm32 = sin * m31 + cos * m32;
+ return dest
+ ._m00(m00)
+ ._m01(cos * m01 - sin * m02)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(cos * m11 - sin * m12)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(m20)
+ ._m21(cos * m21 - sin * m22)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(cos * m31 - sin * m32)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(float) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix4f rotateLocalX(float ang) {
+ return rotateLocalX(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateLocalY(float ang, Matrix4f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm02 = -sin * m00 + cos * m02;
+ float nm12 = -sin * m10 + cos * m12;
+ float nm22 = -sin * m20 + cos * m22;
+ float nm32 = -sin * m30 + cos * m32;
+ return dest
+ ._m00(cos * m00 + sin * m02)
+ ._m01(m01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(cos * m10 + sin * m12)
+ ._m11(m11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(cos * m20 + sin * m22)
+ ._m21(m21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(cos * m30 + sin * m32)
+ ._m31(m31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @return this
+ */
+ public Matrix4f rotateLocalY(float ang) {
+ return rotateLocalY(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(float) rotationZ()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationZ(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateLocalZ(float ang, Matrix4f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm01 = sin * m00 + cos * m01;
+ float nm11 = sin * m10 + cos * m11;
+ float nm21 = sin * m20 + cos * m21;
+ float nm31 = sin * m30 + cos * m31;
+ return dest
+ ._m00(cos * m00 - sin * m01)
+ ._m01(nm01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(cos * m10 - sin * m11)
+ ._m11(nm11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(cos * m20 - sin * m21)
+ ._m21(nm21)
+ ._m22(m22)
+ ._m23(m23)
+ ._m30(cos * m30 - sin * m31)
+ ._m31(nm31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @return this
+ */
+ public Matrix4f rotateLocalZ(float ang) {
+ return rotateLocalZ(ang, this);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4f translate(Vector3fc offset) {
+ return translate(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f translate(Vector3fc offset, Matrix4f dest) {
+ return translate(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f translate(float x, float y, float z, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.translation(x, y, z);
+ return translateGeneric(x, y, z, dest);
+ }
+ private Matrix4f translateGeneric(float x, float y, float z, Matrix4f dest) {
+ MemUtil.INSTANCE.copy(this, dest);
+ return dest
+ ._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))))
+ ._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))))
+ ._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))))
+ ._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))))
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY));
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4f translate(float x, float y, float z) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return translation(x, y, z);
+ return translateGeneric(x, y, z);
+ }
+ private Matrix4f translateGeneric(float x, float y, float z) {
+ return this
+ ._m30(Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))))
+ ._m31(Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))))
+ ._m32(Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))))
+ ._m33(Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33))))
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY));
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4f translateLocal(Vector3fc offset) {
+ return translateLocal(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f translateLocal(Vector3fc offset, Matrix4f dest) {
+ return translateLocal(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f translateLocal(float x, float y, float z, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.translation(x, y, z);
+ return translateLocalGeneric(x, y, z, dest);
+ }
+ private Matrix4f translateLocalGeneric(float x, float y, float z, Matrix4f dest) {
+ float nm00 = m00 + x * m03;
+ float nm01 = m01 + y * m03;
+ float nm02 = m02 + z * m03;
+ float nm10 = m10 + x * m13;
+ float nm11 = m11 + y * m13;
+ float nm12 = m12 + z * m13;
+ float nm20 = m20 + x * m23;
+ float nm21 = m21 + y * m23;
+ float nm22 = m22 + z * m23;
+ float nm30 = m30 + x * m33;
+ float nm31 = m31 + y * m33;
+ float nm32 = m32 + z * m33;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY));
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4f translateLocal(float x, float y, float z) {
+ return translateLocal(x, y, z, this);
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(m00);
+ out.writeFloat(m01);
+ out.writeFloat(m02);
+ out.writeFloat(m03);
+ out.writeFloat(m10);
+ out.writeFloat(m11);
+ out.writeFloat(m12);
+ out.writeFloat(m13);
+ out.writeFloat(m20);
+ out.writeFloat(m21);
+ out.writeFloat(m22);
+ out.writeFloat(m23);
+ out.writeFloat(m30);
+ out.writeFloat(m31);
+ out.writeFloat(m32);
+ out.writeFloat(m33);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ this._m00(in.readFloat())
+ ._m01(in.readFloat())
+ ._m02(in.readFloat())
+ ._m03(in.readFloat())
+ ._m10(in.readFloat())
+ ._m11(in.readFloat())
+ ._m12(in.readFloat())
+ ._m13(in.readFloat())
+ ._m20(in.readFloat())
+ ._m21(in.readFloat())
+ ._m22(in.readFloat())
+ ._m23(in.readFloat())
+ ._m30(in.readFloat())
+ ._m31(in.readFloat())
+ ._m32(in.readFloat())
+ ._m33(in.readFloat())
+ .determineProperties();
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrtho(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return orthoGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f orthoGeneric(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar);
+ float rm30 = (left + right) / (left - right);
+ float rm31 = (top + bottom) / (bottom - top);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest) {
+ return ortho(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ return ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return ortho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return orthoLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f orthoLHGeneric(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear);
+ float rm30 = (left + right) / (left - right);
+ float rm31 = (top + bottom) / (bottom - top);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(float, float, float, float, float, float, boolean) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setOrtho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(2.0f / (right - left))
+ ._m11(2.0f / (top - bottom))
+ ._m22((zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar))
+ ._m30((right + left) / (left - right))
+ ._m31((top + bottom) / (bottom - top))
+ ._m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar))
+ ._properties(PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(float, float, float, float, float, float) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f setOrtho(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return setOrtho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(float, float, float, float, float, float, boolean) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setOrthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(2.0f / (right - left))
+ ._m11(2.0f / (top - bottom))
+ ._m22((zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear))
+ ._m30((right + left) / (left - right))
+ ._m31((top + bottom) / (bottom - top))
+ ._m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar))
+ ._properties(PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(float, float, float, float, float, float) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f setOrthoLH(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return setOrthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, boolean, Matrix4f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4f orthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrthoSymmetric(width, height, zNear, zFar, zZeroToOne);
+ return orthoSymmetricGeneric(width, height, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f orthoSymmetricGeneric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / width;
+ float rm11 = 2.0f / height;
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m20 * rm32 + m30)
+ ._m31(m21 * rm32 + m31)
+ ._m32(m22 * rm32 + m32)
+ ._m33(m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f orthoSymmetric(float width, float height, float zNear, float zFar, Matrix4f dest) {
+ return orthoSymmetric(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, boolean) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f orthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ return orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f orthoSymmetric(float width, float height, float zNear, float zFar) {
+ return orthoSymmetric(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, boolean, Matrix4f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4f orthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrthoSymmetricLH(width, height, zNear, zFar, zZeroToOne);
+ return orthoSymmetricLHGeneric(width, height, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f orthoSymmetricLHGeneric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / width;
+ float rm11 = 2.0f / height;
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m20 * rm32 + m30)
+ ._m31(m21 * rm32 + m31)
+ ._m32(m22 * rm32 + m32)
+ ._m33(m23 * rm32 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20 * rm22)
+ ._m21(m21 * rm22)
+ ._m22(m22 * rm22)
+ ._m23(m23 * rm22)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f orthoSymmetricLH(float width, float height, float zNear, float zFar, Matrix4f dest) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, boolean) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f orthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ return orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f orthoSymmetricLH(float width, float height, float zNear, float zFar) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(float, float, float, float, boolean) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setOrthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(2.0f / width)
+ ._m11(2.0f / height)
+ ._m22((zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar))
+ ._m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar))
+ ._properties(PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(float, float, float, float) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f setOrthoSymmetric(float width, float height, float zNear, float zFar) {
+ return setOrthoSymmetric(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(float, float, float, float, boolean) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setOrthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(2.0f / width)
+ ._m11(2.0f / height)
+ ._m22((zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear))
+ ._m32((zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar))
+ ._properties(PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrthoLH(float, float, float, float, float, float) setOrthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(float, float, float, float) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4f setOrthoSymmetricLH(float width, float height, float zNear, float zFar) {
+ return setOrthoSymmetricLH(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix
+ * and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4f) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(float, float, float, float) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float, Matrix4f)
+ * @see #setOrtho2D(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f ortho2D(float left, float right, float bottom, float top, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrtho2D(left, right, bottom, top);
+ return ortho2DGeneric(left, right, bottom, top, dest);
+ }
+ private Matrix4f ortho2DGeneric(float left, float right, float bottom, float top, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm30 = (right + left) / (left - right);
+ float rm31 = (top + bottom) / (bottom - top);
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(-m20)
+ ._m21(-m21)
+ ._m22(-m22)
+ ._m23(-m23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(float, float, float, float) setOrtho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float)
+ * @see #setOrtho2D(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4f ortho2D(float left, float right, float bottom, float top) {
+ return ortho2D(left, right, bottom, top, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4f) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(float, float, float, float) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float, Matrix4f)
+ * @see #setOrtho2DLH(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f ortho2DLH(float left, float right, float bottom, float top, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setOrtho2DLH(left, right, bottom, top);
+ return ortho2DLHGeneric(left, right, bottom, top, dest);
+ }
+ private Matrix4f ortho2DLHGeneric(float left, float right, float bottom, float top, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm30 = (right + left) / (left - right);
+ float rm31 = (top + bottom) / (bottom - top);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest._m30(m00 * rm30 + m10 * rm31 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m33)
+ ._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(float, float, float, float) setOrtho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float)
+ * @see #setOrtho2DLH(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4f ortho2DLH(float left, float right, float bottom, float top) {
+ return ortho2DLH(left, right, bottom, top, this);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float) setOrtho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2D(float, float, float, float) ortho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float)
+ * @see #ortho2D(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4f setOrtho2D(float left, float right, float bottom, float top) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(2.0f / (right - left))
+ ._m11(2.0f / (top - bottom))
+ ._m22(-1.0f)
+ ._m30((right + left) / (left - right))
+ ._m31((top + bottom) / (bottom - top))
+ ._properties(PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float) setOrthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2DLH(float, float, float, float) ortho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float)
+ * @see #ortho2DLH(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4f setOrtho2DLH(float left, float right, float bottom, float top) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(2.0f / (right - left))
+ ._m11(2.0f / (top - bottom))
+ ._m30((right + left) / (left - right))
+ ._m31((top + bottom) / (bottom - top))
+ ._properties(PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3fc, Vector3fc, Vector3fc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}.
+ *
+ * @see #lookAlong(float, float, float, float, float, float)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4f lookAlong(Vector3fc dir, Vector3fc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3fc, Vector3fc, Vector3fc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}.
+ *
+ * @see #lookAlong(float, float, float, float, float, float)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAlong(Vector3fc dir, Vector3fc up, Matrix4f dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()}
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAlong(dirX, dirY, dirZ, upX, upY, upZ);
+ return lookAlongGeneric(dirX, dirY, dirZ, upX, upY, upZ, dest);
+ }
+
+ private Matrix4f lookAlongGeneric(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4f dest) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+ // perform optimized matrix multiplication
+ // introduce temporaries for dependent results
+ float nm00 = m00 * leftX + m10 * upnX + m20 * dirX;
+ float nm01 = m01 * leftX + m11 * upnX + m21 * dirX;
+ float nm02 = m02 * leftX + m12 * upnX + m22 * dirX;
+ float nm03 = m03 * leftX + m13 * upnX + m23 * dirX;
+ float nm10 = m00 * leftY + m10 * upnY + m20 * dirY;
+ float nm11 = m01 * leftY + m11 * upnY + m21 * dirY;
+ float nm12 = m02 * leftY + m12 * upnY + m22 * dirY;
+ float nm13 = m03 * leftY + m13 * upnY + m23 * dirY;
+ return dest
+ ._m20(m00 * leftZ + m10 * upnZ + m20 * dirZ)
+ ._m21(m01 * leftZ + m11 * upnZ + m21 * dirZ)
+ ._m22(m02 * leftZ + m12 * upnZ + m22 * dirZ)
+ ._m23(m03 * leftZ + m13 * upnZ + m23 * dirZ)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()}
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f lookAlong(float dirX, float dirY, float dirZ,
+ float upX, float upY, float upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc) setLookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(Vector3fc, Vector3fc)}.
+ *
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ * @see #lookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4f setLookAlong(Vector3fc dir, Vector3fc up) {
+ return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(float, float, float, float, float, float, float, float, float)
+ * setLookAt()} with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(float, float, float, float, float, float) lookAlong()}
+ *
+ * @see #setLookAlong(float, float, float, float, float, float)
+ * @see #lookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f setLookAlong(float dirX, float dirY, float dirZ,
+ float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ this._m00(leftX)
+ ._m01(dirY * leftZ - dirZ * leftY)
+ ._m02(dirX)
+ ._m03(0.0f)
+ ._m10(leftY)
+ ._m11(dirZ * leftX - dirX * leftZ)
+ ._m12(dirY)
+ ._m13(0.0f)
+ ._m20(leftZ)
+ ._m21(dirX * leftY - dirY * leftX)
+ ._m22(dirZ)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns
+ * -z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(Vector3fc, Vector3fc, Vector3fc) lookAt()}.
+ *
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4f setLookAt(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return setLookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt}.
+ *
+ * @see #setLookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f setLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+ return this
+ ._m00(leftX)
+ ._m01(upnX)
+ ._m02(dirX)
+ ._m03(0.0f)
+ ._m10(leftY)
+ ._m11(upnY)
+ ._m12(dirY)
+ ._m13(0.0f)
+ ._m20(leftZ)
+ ._m21(upnZ)
+ ._m22(dirZ)
+ ._m23(0.0f)
+ ._m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ))
+ ._m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ))
+ ._m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ))
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAt(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4f dest) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4f lookAt(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}.
+ *
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return lookAtPerspective(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4f lookAtGeneric(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4f dest) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ float rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ float rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ // introduce temporaries for dependent results
+ float nm00 = m00 * leftX + m10 * upnX + m20 * dirX;
+ float nm01 = m01 * leftX + m11 * upnX + m21 * dirX;
+ float nm02 = m02 * leftX + m12 * upnX + m22 * dirX;
+ float nm03 = m03 * leftX + m13 * upnX + m23 * dirX;
+ float nm10 = m00 * leftY + m10 * upnY + m20 * dirY;
+ float nm11 = m01 * leftY + m11 * upnY + m21 * dirY;
+ float nm12 = m02 * leftY + m12 * upnY + m22 * dirY;
+ float nm13 = m03 * leftY + m13 * upnY + m23 * dirY;
+
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ return dest
+ ._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m20(m00 * leftZ + m10 * upnZ + m20 * dirZ)
+ ._m21(m01 * leftZ + m11 * upnZ + m21 * dirZ)
+ ._m22(m02 * leftZ + m12 * upnZ + m22 * dirZ)
+ ._m23(m03 * leftZ + m13 * upnZ + m23 * dirZ)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustum(float, float, float, float, float, float) frustum()} or {@link #perspective(float, float, float, float) perspective()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}.
+ *
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAtPerspective(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4f dest) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+ float rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ float rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ float rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ float nm10 = m00 * leftY;
+ float nm20 = m00 * leftZ;
+ float nm21 = m11 * upnZ;
+ float nm30 = m00 * rm30;
+ float nm31 = m11 * rm31;
+ float nm32 = m22 * rm32 + m32;
+ float nm33 = m23 * rm32;
+ return dest
+ ._m00(m00 * leftX)
+ ._m01(m11 * upnX)
+ ._m02(m22 * dirX)
+ ._m03(m23 * dirX)
+ ._m10(nm10)
+ ._m11(m11 * upnY)
+ ._m12(m22 * dirY)
+ ._m13(m23 * dirY)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(m22 * dirZ)
+ ._m23(m23 * dirZ)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}.
+ *
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f lookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ return lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns
+ * +z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(Vector3fc, Vector3fc, Vector3fc) lookAt()}.
+ *
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4f setLookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return setLookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(float, float, float, float, float, float, float, float, float) lookAtLH}.
+ *
+ * @see #setLookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f setLookAtLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+ this._m00(leftX)
+ ._m01(upnX)
+ ._m02(dirX)
+ ._m03(0.0f)
+ ._m10(leftY)
+ ._m11(upnY)
+ ._m12(dirY)
+ ._m13(0.0f)
+ ._m20(leftZ)
+ ._m21(upnZ)
+ ._m22(dirZ)
+ ._m23(0.0f)
+ ._m30(-(leftX * eyeX + leftY * eyeY + leftZ * eyeZ))
+ ._m31(-(upnX * eyeX + upnY * eyeY + upnZ * eyeZ))
+ ._m32(-(dirX * eyeX + dirY * eyeY + dirZ * eyeZ))
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4f dest) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4f lookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAtLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ else if ((properties & PROPERTY_PERSPECTIVE) != 0)
+ return lookAtPerspectiveLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4f lookAtLHGeneric(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4f dest) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ float rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ float rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ // introduce temporaries for dependent results
+ float nm00 = m00 * leftX + m10 * upnX + m20 * dirX;
+ float nm01 = m01 * leftX + m11 * upnX + m21 * dirX;
+ float nm02 = m02 * leftX + m12 * upnX + m22 * dirX;
+ float nm03 = m03 * leftX + m13 * upnX + m23 * dirX;
+ float nm10 = m00 * leftY + m10 * upnY + m20 * dirY;
+ float nm11 = m01 * leftY + m11 * upnY + m21 * dirY;
+ float nm12 = m02 * leftY + m12 * upnY + m22 * dirY;
+ float nm13 = m03 * leftY + m13 * upnY + m23 * dirY;
+
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ return dest
+ ._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33)
+ ._m20(m00 * leftZ + m10 * upnZ + m20 * dirZ)
+ ._m21(m01 * leftZ + m11 * upnZ + m21 * dirZ)
+ ._m22(m02 * leftZ + m12 * upnZ + m22 * dirZ)
+ ._m23(m03 * leftZ + m13 * upnZ + m23 * dirZ)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f lookAtLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ return lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustumLH(float, float, float, float, float, float) frustumLH()} or {@link #perspectiveLH(float, float, float, float) perspectiveLH()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}.
+ *
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f lookAtPerspectiveLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4f dest) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ float rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ float rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+
+ float nm00 = m00 * leftX;
+ float nm01 = m11 * upnX;
+ float nm02 = m22 * dirX;
+ float nm03 = m23 * dirX;
+ float nm10 = m00 * leftY;
+ float nm11 = m11 * upnY;
+ float nm12 = m22 * dirY;
+ float nm13 = m23 * dirY;
+ float nm20 = m00 * leftZ;
+ float nm21 = m11 * upnZ;
+ float nm22 = m22 * dirZ;
+ float nm23 = m23 * dirZ;
+ float nm30 = m00 * rm30;
+ float nm31 = m11 * rm31;
+ float nm32 = m22 * rm32 + m32;
+ float nm33 = m23 * rm32;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(nm33)
+ ._properties(0);
+ }
+
+ /**
+ * This method is equivalent to calling: translate(w-1-2*x, h-1-2*y, 0).scale(w, h, 1)
+ *
+ * If M
is this
matrix and T
the created transformation matrix,
+ * then the new matrix will be M * T
. So when transforming a
+ * vector v
with the new matrix by using M * T * v
, the
+ * created transformation will be applied first!
+ *
+ * @param x
+ * the tile's x coordinate/index (should be in [0..w)
)
+ * @param y
+ * the tile's y coordinate/index (should be in [0..h)
)
+ * @param w
+ * the number of tiles along the x axis
+ * @param h
+ * the number of tiles along the y axis
+ * @return this
+ */
+ public Matrix4f tile(int x, int y, int w, int h) {
+ return tile(x, y, w, h, this);
+ }
+ public Matrix4f tile(int x, int y, int w, int h, Matrix4f dest) {
+ float tx = w - 1 - (x<<1), ty = h - 1 - (y<<1);
+ return dest
+ ._m30(Math.fma(m00, tx, Math.fma(m10, ty, m30)))
+ ._m31(Math.fma(m01, tx, Math.fma(m11, ty, m31)))
+ ._m32(Math.fma(m02, tx, Math.fma(m12, ty, m32)))
+ ._m33(Math.fma(m03, tx, Math.fma(m13, ty, m33)))
+ ._m00(m00 * w)
+ ._m01(m01 * w)
+ ._m02(m02 * w)
+ ._m03(m03 * w)
+ ._m10(m10 * h)
+ ._m11(m11 * h)
+ ._m12(m12 * h)
+ ._m13(m13 * h)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22(m22)
+ ._m23(m23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(float, float, float, float, boolean) setPerspective}.
+ *
+ * @see #setPerspective(float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4f perspective(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspective(fovy, aspect, zNear, zFar, zZeroToOne);
+ return perspectiveGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f perspectiveGeneric(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ float h = Math.tan(fovy * 0.5f);
+ // calculate right matrix elements
+ float rm00 = 1.0f / (h * aspect);
+ float rm11 = 1.0f / h;
+ float rm22;
+ float rm32;
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ rm22 = e - 1.0f;
+ rm32 = (e - (zZeroToOne ? 1.0f : 2.0f)) * zNear;
+ } else if (nearInf) {
+ float e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0f : 1.0f) - e;
+ rm32 = ((zZeroToOne ? 1.0f : 2.0f) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ float nm20 = m20 * rm22 - m30;
+ float nm21 = m21 * rm22 - m31;
+ float nm22 = m22 * rm22 - m32;
+ float nm23 = m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(float, float, float, float) setPerspective}.
+ *
+ * @see #setPerspective(float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f perspective(float fovy, float aspect, float zNear, float zFar, Matrix4f dest) {
+ return perspective(fovy, aspect, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(float, float, float, float, boolean) setPerspective}.
+ *
+ * @see #setPerspective(float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f perspective(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne) {
+ return perspective(fovy, aspect, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspective(float, float, float, float) setPerspective}.
+ *
+ * @see #setPerspective(float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f perspective(float fovy, float aspect, float zNear, float zFar) {
+ return perspective(fovy, aspect, zNear, zFar, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(float, float, float, float, boolean) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(float, float, float, float, boolean)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4f perspectiveRect(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspectiveRect(width, height, zNear, zFar, zZeroToOne);
+ return perspectiveRectGeneric(width, height, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f perspectiveRectGeneric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ float rm00 = (zNear + zNear) / width;
+ float rm11 = (zNear + zNear) / height;
+ float rm22, rm32;
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ rm22 = e - 1.0f;
+ rm32 = (e - (zZeroToOne ? 1.0f : 2.0f)) * zNear;
+ } else if (nearInf) {
+ float e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0f : 1.0f) - e;
+ rm32 = ((zZeroToOne ? 1.0f : 2.0f) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ float nm20 = m20 * rm22 - m30;
+ float nm21 = m21 * rm22 - m31;
+ float nm22 = m22 * rm22 - m32;
+ float nm23 = m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(float, float, float, float) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(float, float, float, float)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f perspectiveRect(float width, float height, float zNear, float zFar, Matrix4f dest) {
+ return perspectiveRect(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(float, float, float, float, boolean) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(float, float, float, float, boolean)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f perspectiveRect(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ return perspectiveRect(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveRect(float, float, float, float) setPerspectiveRect}.
+ *
+ * @see #setPerspectiveRect(float, float, float, float)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f perspectiveRect(float width, float height, float zNear, float zFar) {
+ return perspectiveRect(width, height, zNear, zFar, this);
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(float, float, float, float, float, float, boolean) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(float, float, float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne);
+ return perspectiveOffCenterGeneric(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f perspectiveOffCenterGeneric(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ float h = Math.tan(fovy * 0.5f);
+ // calculate right matrix elements
+ float xScale = 1.0f / (h * aspect);
+ float yScale = 1.0f / h;
+ float offX = Math.tan(offAngleX), offY = Math.tan(offAngleY);
+ float rm20 = offX * xScale;
+ float rm21 = offY * yScale;
+ float rm22;
+ float rm32;
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ rm22 = e - 1.0f;
+ rm32 = (e - (zZeroToOne ? 1.0f : 2.0f)) * zNear;
+ } else if (nearInf) {
+ float e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0f : 1.0f) - e;
+ rm32 = ((zZeroToOne ? 1.0f : 2.0f) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ float nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30;
+ float nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31;
+ float nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32;
+ float nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33;
+ dest._m00(m00 * xScale)
+ ._m01(m01 * xScale)
+ ._m02(m02 * xScale)
+ ._m03(m03 * xScale)
+ ._m10(m10 * yScale)
+ ._m11(m11 * yScale)
+ ._m12(m12 * yScale)
+ ._m13(m13 * yScale)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION
+ | PROPERTY_ORTHONORMAL | (rm20 == 0.0f && rm21 == 0.0f ? 0 : PROPERTY_PERSPECTIVE)));
+ return dest;
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(float, float, float, float, float, float) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(float, float, float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, Matrix4f dest) {
+ return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(float, float, float, float, float, float, boolean) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(float, float, float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, boolean zZeroToOne) {
+ return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveOffCenter(float, float, float, float, float, float) setPerspectiveOffCenter}.
+ *
+ * @see #setPerspectiveOffCenter(float, float, float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar) {
+ return perspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspective(float, float, float, float, boolean) perspective()}.
+ *
+ * @see #perspective(float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setPerspective(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.zero(this);
+ float h = Math.tan(fovy * 0.5f);
+ this._m00(1.0f / (h * aspect))
+ ._m11(1.0f / h);
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ this._m22(e - 1.0f)
+ ._m32((e - (zZeroToOne ? 1.0f : 2.0f)) * zNear);
+ } else if (nearInf) {
+ float e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0f : 1.0f) - e)
+ ._m32(((zZeroToOne ? 1.0f : 2.0f) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar))
+ ._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ return this
+ ._m23(-1.0f)
+ ._properties(PROPERTY_PERSPECTIVE);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspective(float, float, float, float) perspective()}.
+ *
+ * @see #perspective(float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f setPerspective(float fovy, float aspect, float zNear, float zFar) {
+ return setPerspective(fovy, aspect, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveRect(float, float, float, float, boolean) perspectiveRect()}.
+ *
+ * @see #perspectiveRect(float, float, float, float, boolean)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setPerspectiveRect(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.zero(this);
+ this._m00((zNear + zNear) / width)
+ ._m11((zNear + zNear) / height);
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ this._m22(e - 1.0f)
+ ._m32((e - (zZeroToOne ? 1.0f : 2.0f)) * zNear);
+ } else if (nearInf) {
+ float e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0f : 1.0f) - e)
+ ._m32(((zZeroToOne ? 1.0f : 2.0f) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar))
+ ._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ this._m23(-1.0f)
+ ._properties(PROPERTY_PERSPECTIVE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveRect(float, float, float, float) perspectiveRect()}.
+ *
+ * @see #perspectiveRect(float, float, float, float)
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f setPerspectiveRect(float width, float height, float zNear, float zFar) {
+ return setPerspectiveRect(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed
+ * coordinate system using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveOffCenter(float, float, float, float, float, float) perspectiveOffCenter()}.
+ *
+ * @see #perspectiveOffCenter(float, float, float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f setPerspectiveOffCenter(float fovy, float offAngleX, float offAngleY,
+ float aspect, float zNear, float zFar) {
+ return setPerspectiveOffCenter(fovy, offAngleX, offAngleY, aspect, zNear, zFar, false);
+ }
+ /**
+ * Set this matrix to be an asymmetric off-center perspective projection frustum transformation for a right-handed
+ * coordinate system using the given NDC z range.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveOffCenter(float, float, float, float, float, float) perspectiveOffCenter()}.
+ *
+ * @see #perspectiveOffCenter(float, float, float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setPerspectiveOffCenter(float fovy, float offAngleX, float offAngleY,
+ float aspect, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.zero(this);
+ float h = Math.tan(fovy * 0.5f);
+ float xScale = 1.0f / (h * aspect), yScale = 1.0f / h;
+ float offX = Math.tan(offAngleX), offY = Math.tan(offAngleY);
+ this._m00(xScale)
+ ._m11(yScale)
+ ._m20(offX * xScale)
+ ._m21(offY * yScale);
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ this._m22(e - 1.0f)
+ ._m32((e - (zZeroToOne ? 1.0f : 2.0f)) * zNear);
+ } else if (nearInf) {
+ float e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0f : 1.0f) - e)
+ ._m32(((zZeroToOne ? 1.0f : 2.0f) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar))
+ ._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ this._m23(-1.0f)
+ ._properties(offAngleX == 0.0f && offAngleY == 0.0f ? PROPERTY_PERSPECTIVE : 0);
+ return this;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(float, float, float, float, boolean) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f perspectiveLH(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setPerspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne);
+ return perspectiveLHGeneric(fovy, aspect, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f perspectiveLHGeneric(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ float h = Math.tan(fovy * 0.5f);
+ // calculate right matrix elements
+ float rm00 = 1.0f / (h * aspect);
+ float rm11 = 1.0f / h;
+ float rm22;
+ float rm32;
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ rm22 = 1.0f - e;
+ rm32 = (e - (zZeroToOne ? 1.0f : 2.0f)) * zNear;
+ } else if (nearInf) {
+ float e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0f : 1.0f) - e;
+ rm32 = ((zZeroToOne ? 1.0f : 2.0f) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ float nm20 = m20 * rm22 + m30;
+ float nm21 = m21 * rm22 + m31;
+ float nm22 = m22 * rm22 + m32;
+ float nm23 = m23 * rm22 + m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_AFFINE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(float, float, float, float, boolean) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f perspectiveLH(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne) {
+ return perspectiveLH(fovy, aspect, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(float, float, float, float) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f perspectiveLH(float fovy, float aspect, float zNear, float zFar, Matrix4f dest) {
+ return perspectiveLH(fovy, aspect, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setPerspectiveLH(float, float, float, float) setPerspectiveLH}.
+ *
+ * @see #setPerspectiveLH(float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f perspectiveLH(float fovy, float aspect, float zNear, float zFar) {
+ return perspectiveLH(fovy, aspect, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveLH(float, float, float, float, boolean) perspectiveLH()}.
+ *
+ * @see #perspectiveLH(float, float, float, float, boolean)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setPerspectiveLH(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.zero(this);
+ float h = Math.tan(fovy * 0.5f);
+ this._m00(1.0f / (h * aspect))
+ ._m11(1.0f / h);
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ this._m22(1.0f - e)
+ ._m32((e - (zZeroToOne ? 1.0f : 2.0f)) * zNear);
+ } else if (nearInf) {
+ float e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0f : 1.0f) - e)
+ ._m32(((zZeroToOne ? 1.0f : 2.0f) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear))
+ ._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ this._m23(1.0f)
+ ._properties(PROPERTY_PERSPECTIVE);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective projection transformation to an existing transformation,
+ * use {@link #perspectiveLH(float, float, float, float) perspectiveLH()}.
+ *
+ * @see #perspectiveLH(float, float, float, float)
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f setPerspectiveLH(float fovy, float aspect, float zNear, float zFar) {
+ return setPerspectiveLH(fovy, aspect, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(float, float, float, float, float, float, boolean) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f frustum(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setFrustum(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return frustumGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f frustumGeneric(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = (zNear + zNear) / (right - left);
+ float rm11 = (zNear + zNear) / (top - bottom);
+ float rm20 = (right + left) / (right - left);
+ float rm21 = (top + bottom) / (top - bottom);
+ float rm22;
+ float rm32;
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ rm22 = e - 1.0f;
+ rm32 = (e - (zZeroToOne ? 1.0f : 2.0f)) * zNear;
+ } else if (nearInf) {
+ float e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0f : 1.0f) - e;
+ rm32 = ((zZeroToOne ? 1.0f : 2.0f) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ float nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 - m30;
+ float nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 - m31;
+ float nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 - m32;
+ float nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 - m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(float, float, float, float, float, float) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f frustum(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest) {
+ return frustum(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(float, float, float, float, float, float, boolean) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f frustum(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ return frustum(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustum(float, float, float, float, float, float) setFrustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustum(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f frustum(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return frustum(left, right, bottom, top, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustum(float, float, float, float, float, float, boolean) frustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustum(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setFrustum(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00((zNear + zNear) / (right - left))
+ ._m11((zNear + zNear) / (top - bottom))
+ ._m20((right + left) / (right - left))
+ ._m21((top + bottom) / (top - bottom));
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ this._m22(e - 1.0f)
+ ._m32((e - (zZeroToOne ? 1.0f : 2.0f)) * zNear);
+ } else if (nearInf) {
+ float e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0f : 1.0f) - e)
+ ._m32(((zZeroToOne ? 1.0f : 2.0f) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zNear - zFar))
+ ._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ this._m23(-1.0f)
+ ._m33(0.0f)
+ ._properties(this.m20 == 0.0f && this.m21 == 0.0f ? PROPERTY_PERSPECTIVE : 0);
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustum(float, float, float, float, float, float) frustum()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustum(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f setFrustum(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return setFrustum(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(float, float, float, float, float, float, boolean) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f frustumLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setFrustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne);
+ return frustumLHGeneric(left, right, bottom, top, zNear, zFar, zZeroToOne, dest);
+ }
+ private Matrix4f frustumLHGeneric(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest) {
+ // calculate right matrix elements
+ float rm00 = (zNear + zNear) / (right - left);
+ float rm11 = (zNear + zNear) / (top - bottom);
+ float rm20 = (right + left) / (right - left);
+ float rm21 = (top + bottom) / (top - bottom);
+ float rm22;
+ float rm32;
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ rm22 = 1.0f - e;
+ rm32 = (e - (zZeroToOne ? 1.0f : 2.0f)) * zNear;
+ } else if (nearInf) {
+ float e = 1E-6f;
+ rm22 = (zZeroToOne ? 0.0f : 1.0f) - e;
+ rm32 = ((zZeroToOne ? 1.0f : 2.0f) - e) * zFar;
+ } else {
+ rm22 = (zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear);
+ rm32 = (zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar);
+ }
+ // perform optimized matrix multiplication
+ float nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30;
+ float nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31;
+ float nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32;
+ float nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33;
+ dest._m00(m00 * rm00)
+ ._m01(m01 * rm00)
+ ._m02(m02 * rm00)
+ ._m03(m03 * rm00)
+ ._m10(m10 * rm11)
+ ._m11(m11 * rm11)
+ ._m12(m12 * rm11)
+ ._m13(m13 * rm11)
+ ._m30(m20 * rm32)
+ ._m31(m21 * rm32)
+ ._m32(m22 * rm32)
+ ._m33(m23 * rm32)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(float, float, float, float, float, float, boolean) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f frustumLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ return frustumLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(float, float, float, float, float, float) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f frustumLH(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest) {
+ return frustumLH(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * In order to set the matrix to a perspective frustum transformation without post-multiplying,
+ * use {@link #setFrustumLH(float, float, float, float, float, float) setFrustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setFrustumLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f frustumLH(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return frustumLH(left, right, bottom, top, zNear, zFar, this);
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustumLH(float, float, float, float, float, float, boolean) frustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustumLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4f setFrustumLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00((zNear + zNear) / (right - left))
+ ._m11((zNear + zNear) / (top - bottom))
+ ._m20((right + left) / (right - left))
+ ._m21((top + bottom) / (top - bottom));
+ boolean farInf = zFar > 0 && Float.isInfinite(zFar);
+ boolean nearInf = zNear > 0 && Float.isInfinite(zNear);
+ if (farInf) {
+ // See: "Infinite Projection Matrix" (http://www.terathon.com/gdc07_lengyel.pdf)
+ float e = 1E-6f;
+ this._m22(1.0f - e)
+ ._m32((e - (zZeroToOne ? 1.0f : 2.0f)) * zNear);
+ } else if (nearInf) {
+ float e = 1E-6f;
+ this._m22((zZeroToOne ? 0.0f : 1.0f) - e)
+ ._m32(((zZeroToOne ? 1.0f : 2.0f) - e) * zFar);
+ } else {
+ this._m22((zZeroToOne ? zFar : zFar + zNear) / (zFar - zNear))
+ ._m32((zZeroToOne ? zFar : zFar + zFar) * zNear / (zNear - zFar));
+ }
+ return this
+ ._m23(1.0f)
+ ._m33(0.0f)
+ ._properties(0);
+ }
+
+ /**
+ * Set this matrix to be an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the perspective frustum transformation to an existing transformation,
+ * use {@link #frustumLH(float, float, float, float, float, float) frustumLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #frustumLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ public Matrix4f setFrustumLH(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return setFrustumLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to represent a perspective projection equivalent to the given intrinsic camera calibration parameters.
+ * The resulting matrix will be suited for a right-handed coordinate system using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * See: https://en.wikipedia.org/
+ *
+ * Reference: http://ksimek.github.io/
+ *
+ * @param alphaX
+ * specifies the focal length and scale along the X axis
+ * @param alphaY
+ * specifies the focal length and scale along the Y axis
+ * @param gamma
+ * the skew coefficient between the X and Y axis (may be 0
)
+ * @param u0
+ * the X coordinate of the principal point in image/sensor units
+ * @param v0
+ * the Y coordinate of the principal point in image/sensor units
+ * @param imgWidth
+ * the width of the sensor/image image/sensor units
+ * @param imgHeight
+ * the height of the sensor/image image/sensor units
+ * @param near
+ * the distance to the near plane
+ * @param far
+ * the distance to the far plane
+ * @return this
+ */
+ public Matrix4f setFromIntrinsic(float alphaX, float alphaY, float gamma, float u0, float v0, int imgWidth, int imgHeight, float near, float far) {
+ float l00 = 2.0f / imgWidth;
+ float l11 = 2.0f / imgHeight;
+ float l22 = 2.0f / (near - far);
+ this.m00 = l00 * alphaX;
+ this.m01 = 0.0f;
+ this.m02 = 0.0f;
+ this.m03 = 0.0f;
+ this.m10 = l00 * gamma;
+ this.m11 = l11 * alphaY;
+ this.m12 = 0.0f;
+ this.m13 = 0.0f;
+ this.m20 = l00 * u0 - 1.0f;
+ this.m21 = l11 * v0 - 1.0f;
+ this.m22 = l22 * -(near + far) + (far + near) / (near - far);
+ this.m23 = -1.0f;
+ this.m30 = 0.0f;
+ this.m31 = 0.0f;
+ this.m32 = l22 * -near * far;
+ this.m33 = 0.0f;
+ this.properties = PROPERTY_PERSPECTIVE;
+ return this;
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotate(Quaternionfc quat, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(quat);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(quat, dest);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAffine(quat, dest);
+ return rotateGeneric(quat, dest);
+ }
+ private Matrix4f rotateGeneric(Quaternionfc quat, Matrix4f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = -dzw + dxy;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ float nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ return dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4f rotate(Quaternionfc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this {@link #isAffine() affine} matrix and store
+ * the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateAffine(Quaternionfc quat, Matrix4f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = -dzw + dxy;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ return dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0f)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4f rotateAffine(Quaternionfc quat) {
+ return rotateAffine(quat, this);
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateTranslation(Quaternionfc quat, Matrix4f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = -dzw + dxy;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ return dest
+ ._m20(rm20)
+ ._m21(rm21)
+ ._m22(rm22)
+ ._m23(0.0f)
+ ._m00(rm00)
+ ._m01(rm01)
+ ._m02(rm02)
+ ._m03(0.0f)
+ ._m10(rm10)
+ ._m11(rm11)
+ ._m12(rm12)
+ ._m13(0.0f)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this matrix while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4f rotateAround(Quaternionfc quat, float ox, float oy, float oz) {
+ return rotateAround(quat, ox, oy, oz, this);
+ }
+
+ public Matrix4f rotateAroundAffine(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = -dzw + dxy;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ float tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ float tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0f)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
+ ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
+ ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
+ ._m33(1.0f)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ public Matrix4f rotateAround(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return rotationAround(quat, ox, oy, oz);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return rotateAroundAffine(quat, ox, oy, oz, dest);
+ return rotateAroundGeneric(quat, ox, oy, oz, dest);
+ }
+ private Matrix4f rotateAroundGeneric(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = -dzw + dxy;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ float tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ float tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ float nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
+ ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
+ ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a transformation composed of a rotation of the specified {@link Quaternionfc} while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4f rotationAround(Quaternionfc quat, float ox, float oy, float oz) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ this._m20(dyw + dxz)
+ ._m21(dyz - dxw)
+ ._m22(z2 - y2 - x2 + w2)
+ ._m23(0.0f)
+ ._m00(w2 + x2 - z2 - y2)
+ ._m01(dxy + dzw)
+ ._m02(dxz - dyw)
+ ._m03(0.0f)
+ ._m10(-dzw + dxy)
+ ._m11(y2 - z2 + w2 - x2)
+ ._m12(dyz + dxw)
+ ._m13(0.0f)
+ ._m30(-m00 * ox - m10 * oy - m20 * oz + ox)
+ ._m31(-m01 * ox - m11 * oy - m21 * oz + oy)
+ ._m32(-m02 * ox - m12 * oy - m22 * oz + oz)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Pre-multiply the rotation transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateLocal(Quaternionfc quat, Matrix4f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float lm00 = w2 + x2 - z2 - y2;
+ float lm01 = dxy + dzw;
+ float lm02 = dxz - dyw;
+ float lm10 = -dzw + dxy;
+ float lm11 = y2 - z2 + w2 - x2;
+ float lm12 = dyz + dxw;
+ float lm20 = dyw + dxz;
+ float lm21 = dyz - dxw;
+ float lm22 = z2 - y2 - x2 + w2;
+ float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ float nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ float nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ float nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(m03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(m13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(m23)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ }
+
+ /**
+ * Pre-multiply the rotation transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4f rotateLocal(Quaternionfc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ public Matrix4f rotateAroundLocal(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest) {
+ float w2 = quat.w() * quat.w();
+ float x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y();
+ float z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w();
+ float xy = quat.x() * quat.y();
+ float xz = quat.x() * quat.z();
+ float yw = quat.y() * quat.w();
+ float yz = quat.y() * quat.z();
+ float xw = quat.x() * quat.w();
+ float lm00 = w2 + x2 - z2 - y2;
+ float lm01 = xy + zw + zw + xy;
+ float lm02 = xz - yw + xz - yw;
+ float lm10 = -zw + xy - zw + xy;
+ float lm11 = y2 - z2 + w2 - x2;
+ float lm12 = yz + yz + xw + xw;
+ float lm20 = yw + xz + xz + yw;
+ float lm21 = yz + yz - xw - xw;
+ float lm22 = z2 - y2 - x2 + w2;
+ float tm00 = m00 - ox * m03;
+ float tm01 = m01 - oy * m03;
+ float tm02 = m02 - oz * m03;
+ float tm10 = m10 - ox * m13;
+ float tm11 = m11 - oy * m13;
+ float tm12 = m12 - oz * m13;
+ float tm20 = m20 - ox * m23;
+ float tm21 = m21 - oy * m23;
+ float tm22 = m22 - oz * m23;
+ float tm30 = m30 - ox * m33;
+ float tm31 = m31 - oy * m33;
+ float tm32 = m32 - oz * m33;
+ dest._m00(lm00 * tm00 + lm10 * tm01 + lm20 * tm02 + ox * m03)
+ ._m01(lm01 * tm00 + lm11 * tm01 + lm21 * tm02 + oy * m03)
+ ._m02(lm02 * tm00 + lm12 * tm01 + lm22 * tm02 + oz * m03)
+ ._m03(m03)
+ ._m10(lm00 * tm10 + lm10 * tm11 + lm20 * tm12 + ox * m13)
+ ._m11(lm01 * tm10 + lm11 * tm11 + lm21 * tm12 + oy * m13)
+ ._m12(lm02 * tm10 + lm12 * tm11 + lm22 * tm12 + oz * m13)
+ ._m13(m13)
+ ._m20(lm00 * tm20 + lm10 * tm21 + lm20 * tm22 + ox * m23)
+ ._m21(lm01 * tm20 + lm11 * tm21 + lm21 * tm22 + oy * m23)
+ ._m22(lm02 * tm20 + lm12 * tm21 + lm22 * tm22 + oz * m23)
+ ._m23(m23)
+ ._m30(lm00 * tm30 + lm10 * tm31 + lm20 * tm32 + ox * m33)
+ ._m31(lm01 * tm30 + lm11 * tm31 + lm21 * tm32 + oy * m33)
+ ._m32(lm02 * tm30 + lm12 * tm31 + lm22 * tm32 + oz * m33)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation transformation of the given {@link Quaternionfc} to this matrix while using (ox, oy, oz)
+ * as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * This method is equivalent to calling: translateLocal(-ox, -oy, -oz).rotateLocal(quat).translateLocal(ox, oy, oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4f rotateAroundLocal(Quaternionfc quat, float ox, float oy, float oz) {
+ return rotateAroundLocal(quat, ox, oy, oz, this);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4f rotate(AxisAngle4f axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotate(AxisAngle4f axisAngle, Matrix4f dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis-angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(float, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4f rotate(float angle, Vector3fc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis-angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(float, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotate(float angle, Vector3fc axis, Matrix4f dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ public Vector4f unproject(float winX, float winY, float winZ, int[] viewport, Vector4f dest) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float c = m00 * m13 - m03 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float e = m01 * m13 - m03 * m11;
+ float f = m02 * m13 - m03 * m12;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float i = m20 * m33 - m23 * m30;
+ float j = m21 * m32 - m22 * m31;
+ float k = m21 * m33 - m23 * m31;
+ float l = m22 * m33 - m23 * m32;
+ float det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0f / det;
+ float im00 = ( m11 * l - m12 * k + m13 * j) * det;
+ float im01 = (-m01 * l + m02 * k - m03 * j) * det;
+ float im02 = ( m31 * f - m32 * e + m33 * d) * det;
+ float im03 = (-m21 * f + m22 * e - m23 * d) * det;
+ float im10 = (-m10 * l + m12 * i - m13 * h) * det;
+ float im11 = ( m00 * l - m02 * i + m03 * h) * det;
+ float im12 = (-m30 * f + m32 * c - m33 * b) * det;
+ float im13 = ( m20 * f - m22 * c + m23 * b) * det;
+ float im20 = ( m10 * k - m11 * i + m13 * g) * det;
+ float im21 = (-m00 * k + m01 * i - m03 * g) * det;
+ float im22 = ( m30 * e - m31 * c + m33 * a) * det;
+ float im23 = (-m20 * e + m21 * c - m23 * a) * det;
+ float im30 = (-m10 * j + m11 * h - m12 * g) * det;
+ float im31 = ( m00 * j - m01 * h + m02 * g) * det;
+ float im32 = (-m30 * d + m31 * b - m32 * a) * det;
+ float im33 = ( m20 * d - m21 * b + m22 * a) * det;
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ float ndcZ = winZ+winZ-1.0f;
+ float invW = 1.0f / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33);
+ return dest.set((im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW,
+ (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW,
+ (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW,
+ 1.0f);
+ }
+
+ public Vector3f unproject(float winX, float winY, float winZ, int[] viewport, Vector3f dest) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float c = m00 * m13 - m03 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float e = m01 * m13 - m03 * m11;
+ float f = m02 * m13 - m03 * m12;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float i = m20 * m33 - m23 * m30;
+ float j = m21 * m32 - m22 * m31;
+ float k = m21 * m33 - m23 * m31;
+ float l = m22 * m33 - m23 * m32;
+ float det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0f / det;
+ float im00 = ( m11 * l - m12 * k + m13 * j) * det;
+ float im01 = (-m01 * l + m02 * k - m03 * j) * det;
+ float im02 = ( m31 * f - m32 * e + m33 * d) * det;
+ float im03 = (-m21 * f + m22 * e - m23 * d) * det;
+ float im10 = (-m10 * l + m12 * i - m13 * h) * det;
+ float im11 = ( m00 * l - m02 * i + m03 * h) * det;
+ float im12 = (-m30 * f + m32 * c - m33 * b) * det;
+ float im13 = ( m20 * f - m22 * c + m23 * b) * det;
+ float im20 = ( m10 * k - m11 * i + m13 * g) * det;
+ float im21 = (-m00 * k + m01 * i - m03 * g) * det;
+ float im22 = ( m30 * e - m31 * c + m33 * a) * det;
+ float im23 = (-m20 * e + m21 * c - m23 * a) * det;
+ float im30 = (-m10 * j + m11 * h - m12 * g) * det;
+ float im31 = ( m00 * j - m01 * h + m02 * g) * det;
+ float im32 = (-m30 * d + m31 * b - m32 * a) * det;
+ float im33 = ( m20 * d - m21 * b + m22 * a) * det;
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ float ndcZ = winZ+winZ-1.0f;
+ float invW = 1.0f / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33);
+ return dest.set((im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW,
+ (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW,
+ (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW);
+ }
+
+ public Vector4f unproject(Vector3fc winCoords, int[] viewport, Vector4f dest) {
+ return unproject(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Vector3f unproject(Vector3fc winCoords, int[] viewport, Vector3f dest) {
+ return unproject(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Matrix4f unprojectRay(float winX, float winY, int[] viewport, Vector3f originDest, Vector3f dirDest) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float c = m00 * m13 - m03 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float e = m01 * m13 - m03 * m11;
+ float f = m02 * m13 - m03 * m12;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float i = m20 * m33 - m23 * m30;
+ float j = m21 * m32 - m22 * m31;
+ float k = m21 * m33 - m23 * m31;
+ float l = m22 * m33 - m23 * m32;
+ float det = a * l - b * k + c * j + d * i - e * h + f * g;
+ det = 1.0f / det;
+ float im00 = ( m11 * l - m12 * k + m13 * j) * det;
+ float im01 = (-m01 * l + m02 * k - m03 * j) * det;
+ float im02 = ( m31 * f - m32 * e + m33 * d) * det;
+ float im03 = (-m21 * f + m22 * e - m23 * d) * det;
+ float im10 = (-m10 * l + m12 * i - m13 * h) * det;
+ float im11 = ( m00 * l - m02 * i + m03 * h) * det;
+ float im12 = (-m30 * f + m32 * c - m33 * b) * det;
+ float im13 = ( m20 * f - m22 * c + m23 * b) * det;
+ float im20 = ( m10 * k - m11 * i + m13 * g) * det;
+ float im21 = (-m00 * k + m01 * i - m03 * g) * det;
+ float im22 = ( m30 * e - m31 * c + m33 * a) * det;
+ float im23 = (-m20 * e + m21 * c - m23 * a) * det;
+ float im30 = (-m10 * j + m11 * h - m12 * g) * det;
+ float im31 = ( m00 * j - m01 * h + m02 * g) * det;
+ float im32 = (-m30 * d + m31 * b - m32 * a) * det;
+ float im33 = ( m20 * d - m21 * b + m22 * a) * det;
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ float px = im00 * ndcX + im10 * ndcY + im30;
+ float py = im01 * ndcX + im11 * ndcY + im31;
+ float pz = im02 * ndcX + im12 * ndcY + im32;
+ float invNearW = 1.0f / (im03 * ndcX + im13 * ndcY - im23 + im33);
+ float nearX = (px - im20) * invNearW;
+ float nearY = (py - im21) * invNearW;
+ float nearZ = (pz - im22) * invNearW;
+ float invW0 = 1.0f / (im03 * ndcX + im13 * ndcY + im33);
+ float x0 = px * invW0;
+ float y0 = py * invW0;
+ float z0 = pz * invW0;
+ originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ;
+ dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ;
+ return this;
+ }
+
+ public Matrix4f unprojectRay(Vector2fc winCoords, int[] viewport, Vector3f originDest, Vector3f dirDest) {
+ return unprojectRay(winCoords.x(), winCoords.y(), viewport, originDest, dirDest);
+ }
+
+ public Vector4f unprojectInv(Vector3fc winCoords, int[] viewport, Vector4f dest) {
+ return unprojectInv(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Vector4f unprojectInv(float winX, float winY, float winZ, int[] viewport, Vector4f dest) {
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ float ndcZ = winZ+winZ-1.0f;
+ float invW = 1.0f / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33);
+ return dest.set((m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW,
+ (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW,
+ (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW,
+ 1.0f);
+ }
+
+ public Matrix4f unprojectInvRay(Vector2fc winCoords, int[] viewport, Vector3f originDest, Vector3f dirDest) {
+ return unprojectInvRay(winCoords.x(), winCoords.y(), viewport, originDest, dirDest);
+ }
+
+ public Matrix4f unprojectInvRay(float winX, float winY, int[] viewport, Vector3f originDest, Vector3f dirDest) {
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ float px = m00 * ndcX + m10 * ndcY + m30;
+ float py = m01 * ndcX + m11 * ndcY + m31;
+ float pz = m02 * ndcX + m12 * ndcY + m32;
+ float invNearW = 1.0f / (m03 * ndcX + m13 * ndcY - m23 + m33);
+ float nearX = (px - m20) * invNearW;
+ float nearY = (py - m21) * invNearW;
+ float nearZ = (pz - m22) * invNearW;
+ float invW0 = 1.0f / (m03 * ndcX + m13 * ndcY + m33);
+ float x0 = px * invW0;
+ float y0 = py * invW0;
+ float z0 = pz * invW0;
+ originDest.x = nearX; originDest.y = nearY; originDest.z = nearZ;
+ dirDest.x = x0 - nearX; dirDest.y = y0 - nearY; dirDest.z = z0 - nearZ;
+ return this;
+ }
+
+ public Vector3f unprojectInv(Vector3fc winCoords, int[] viewport, Vector3f dest) {
+ return unprojectInv(winCoords.x(), winCoords.y(), winCoords.z(), viewport, dest);
+ }
+
+ public Vector3f unprojectInv(float winX, float winY, float winZ, int[] viewport, Vector3f dest) {
+ float ndcX = (winX-viewport[0])/viewport[2]*2.0f-1.0f;
+ float ndcY = (winY-viewport[1])/viewport[3]*2.0f-1.0f;
+ float ndcZ = winZ+winZ-1.0f;
+ float invW = 1.0f / (m03 * ndcX + m13 * ndcY + m23 * ndcZ + m33);
+ return dest.set((m00 * ndcX + m10 * ndcY + m20 * ndcZ + m30) * invW,
+ (m01 * ndcX + m11 * ndcY + m21 * ndcZ + m31) * invW,
+ (m02 * ndcX + m12 * ndcY + m22 * ndcZ + m32) * invW);
+ }
+
+ public Vector4f project(float x, float y, float z, int[] viewport, Vector4f winCoordsDest) {
+ float invW = 1.0f / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)));
+ float nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW;
+ float ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW;
+ float nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW;
+ return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5f, 0.5f), viewport[2], viewport[0]),
+ Math.fma(Math.fma(ny, 0.5f, 0.5f), viewport[3], viewport[1]),
+ Math.fma(0.5f, nz, 0.5f),
+ 1.0f);
+ }
+
+ public Vector3f project(float x, float y, float z, int[] viewport, Vector3f winCoordsDest) {
+ float invW = 1.0f / Math.fma(m03, x, Math.fma(m13, y, Math.fma(m23, z, m33)));
+ float nx = Math.fma(m00, x, Math.fma(m10, y, Math.fma(m20, z, m30))) * invW;
+ float ny = Math.fma(m01, x, Math.fma(m11, y, Math.fma(m21, z, m31))) * invW;
+ float nz = Math.fma(m02, x, Math.fma(m12, y, Math.fma(m22, z, m32))) * invW;
+ winCoordsDest.x = Math.fma(Math.fma(nx, 0.5f, 0.5f), viewport[2], viewport[0]);
+ winCoordsDest.y = Math.fma(Math.fma(ny, 0.5f, 0.5f), viewport[3], viewport[1]);
+ winCoordsDest.z = Math.fma(0.5f, nz, 0.5f);
+ return winCoordsDest;
+ }
+
+ public Vector4f project(Vector3fc position, int[] viewport, Vector4f winCoordsDest) {
+ return project(position.x(), position.y(), position.z(), viewport, winCoordsDest);
+ }
+
+ public Vector3f project(Vector3fc position, int[] viewport, Vector3f winCoordsDest) {
+ return project(position.x(), position.y(), position.z(), viewport, winCoordsDest);
+ }
+
+ public Matrix4f reflect(float a, float b, float c, float d, Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.reflection(a, b, c, d);
+ else if ((properties & PROPERTY_AFFINE) != 0)
+ return reflectAffine(a, b, c, d, dest);
+ return reflectGeneric(a, b, c, d, dest);
+ }
+ private Matrix4f reflectAffine(float a, float b, float c, float d, Matrix4f dest) {
+ float da = a + a, db = b + b, dc = c + c, dd = d + d;
+ float rm00 = 1.0f - da * a;
+ float rm01 = -da * b;
+ float rm02 = -da * c;
+ float rm10 = -db * a;
+ float rm11 = 1.0f - db * b;
+ float rm12 = -db * c;
+ float rm20 = -dc * a;
+ float rm21 = -dc * b;
+ float rm22 = 1.0f - dc * c;
+ float rm30 = -dd * a;
+ float rm31 = -dd * b;
+ float rm32 = -dd * c;
+ // matrix multiplication
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m33);
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(0.0f)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+ private Matrix4f reflectGeneric(float a, float b, float c, float d, Matrix4f dest) {
+ float da = a + a, db = b + b, dc = c + c, dd = d + d;
+ float rm00 = 1.0f - da * a;
+ float rm01 = -da * b;
+ float rm02 = -da * c;
+ float rm10 = -db * a;
+ float rm11 = 1.0f - db * b;
+ float rm12 = -db * c;
+ float rm20 = -dc * a;
+ float rm21 = -dc * b;
+ float rm22 = 1.0f - dc * c;
+ float rm30 = -dd * a;
+ float rm31 = -dd * b;
+ float rm32 = -dd * c;
+ // matrix multiplication
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33);
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ float nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4f reflect(float a, float b, float c, float d) {
+ return reflect(a, b, c, d, this);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4f reflect(float nx, float ny, float nz, float px, float py, float pz) {
+ return reflect(nx, ny, nz, px, py, pz, this);
+ }
+
+ public Matrix4f reflect(float nx, float ny, float nz, float px, float py, float pz, Matrix4f dest) {
+ float invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ float nnx = nx * invLength;
+ float nny = ny * invLength;
+ float nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4f reflect(Vector3fc normal, Vector3fc point) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4f reflect(Quaternionfc orientation, Vector3fc point) {
+ return reflect(orientation, point, this);
+ }
+
+ public Matrix4f reflect(Quaternionfc orientation, Vector3fc point, Matrix4f dest) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ float normalX = (float) (orientation.x() * num3 + orientation.w() * num2);
+ float normalY = (float) (orientation.y() * num3 - orientation.w() * num1);
+ float normalZ = (float) (1.0 - (orientation.x() * num1 + orientation.y() * num2));
+ return reflect(normalX, normalY, normalZ, point.x(), point.y(), point.z(), dest);
+ }
+
+ public Matrix4f reflect(Vector3fc normal, Vector3fc point, Matrix4f dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z(), dest);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4f reflection(float a, float b, float c, float d) {
+ float da = a + a, db = b + b, dc = c + c, dd = d + d;
+ this._m00(1.0f - da * a)
+ ._m01(-da * b)
+ ._m02(-da * c)
+ ._m03(0.0f)
+ ._m10(-db * a)
+ ._m11(1.0f - db * b)
+ ._m12(-db * c)
+ ._m13(0.0f)
+ ._m20(-dc * a)
+ ._m21(-dc * b)
+ ._m22(1.0f - dc * c)
+ ._m23(0.0f)
+ ._m30(-dd * a)
+ ._m31(-dd * b)
+ ._m32(-dd * c)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4f reflection(float nx, float ny, float nz, float px, float py, float pz) {
+ float invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ float nnx = nx * invLength;
+ float nny = ny * invLength;
+ float nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4f reflection(Vector3fc normal, Vector3fc point) {
+ return reflection(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4f reflection(Quaternionfc orientation, Vector3fc point) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ float normalX = (float) (orientation.x() * num3 + orientation.w() * num2);
+ float normalY = (float) (orientation.y() * num3 - orientation.w() * num1);
+ float normalZ = (float) (1.0 - (orientation.x() * num1 + orientation.y() * num2));
+ return reflection(normalX, normalY, normalZ, point.x(), point.y(), point.z());
+ }
+
+ public Vector4f getRow(int row, Vector4f dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ return dest.set(m00, m10, m20, m30);
+ case 1:
+ return dest.set(m01, m11, m21, m31);
+ case 2:
+ return dest.set(m02, m12, m22, m32);
+ case 3:
+ return dest.set(m03, m13, m23, m33);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public Vector3f getRow(int row, Vector3f dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ return dest.set(m00, m10, m20);
+ case 1:
+ return dest.set(m01, m11, m21);
+ case 2:
+ return dest.set(m02, m12, m22);
+ case 3:
+ return dest.set(m03, m13, m23);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..3]
+ */
+ public Matrix4f setRow(int row, Vector4fc src) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ return _m00(src.x())._m10(src.y())._m20(src.z())._m30(src.w())._properties(0);
+ case 1:
+ return _m01(src.x())._m11(src.y())._m21(src.z())._m31(src.w())._properties(0);
+ case 2:
+ return _m02(src.x())._m12(src.y())._m22(src.z())._m32(src.w())._properties(0);
+ case 3:
+ return _m03(src.x())._m13(src.y())._m23(src.z())._m33(src.w())._properties(0);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public Vector4f getColumn(int column, Vector4f dest) throws IndexOutOfBoundsException {
+ return MemUtil.INSTANCE.getColumn(this, column, dest);
+ }
+
+ public Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ return dest.set(m00, m01, m02);
+ case 1:
+ return dest.set(m10, m11, m12);
+ case 2:
+ return dest.set(m20, m21, m22);
+ case 3:
+ return dest.set(m30, m31, m32);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ public Matrix4f setColumn(int column, Vector4fc src) throws IndexOutOfBoundsException {
+ if (src instanceof Vector4f)
+ return MemUtil.INSTANCE.setColumn((Vector4f) src, column, this)._properties(0);
+ return MemUtil.INSTANCE.setColumn(src, column, this)._properties(0);
+ }
+
+ public float get(int column, int row) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given column and row to the specified value.
+ *
+ * @param column
+ * the colum index in [0..3]
+ * @param row
+ * the row index in [0..3]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix4f set(int column, int row, float value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ public float getRowColumn(int row, int column) {
+ return MemUtil.INSTANCE.get(this, column, row);
+ }
+
+ /**
+ * Set the matrix element at the given row and column to the specified value.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param column
+ * the colum index in [0..3]
+ * @param value
+ * the value
+ * @return this
+ */
+ public Matrix4f setRowColumn(int row, int column, float value) {
+ return MemUtil.INSTANCE.set(this, column, row, value);
+ }
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into the upper left 3x3 submatrix of this
.
+ * All other values of this
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4f)} to set a given Matrix4f to only the upper left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see #set3x3(Matrix4f)
+ *
+ * @return this
+ */
+ public Matrix4f normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into the upper left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4f)} to set a given Matrix4f to only the upper left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see #set3x3(Matrix4f)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f normal(Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix4f normalOrthonormal(Matrix4f dest) {
+ if (dest != this)
+ dest.set(this);
+ return dest._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ }
+ private Matrix4f normalGeneric(Matrix4f dest) {
+ float m00m11 = m00 * m11;
+ float m01m10 = m01 * m10;
+ float m02m10 = m02 * m10;
+ float m00m12 = m00 * m12;
+ float m01m12 = m01 * m12;
+ float m02m11 = m02 * m11;
+ float det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ float s = 1.0f / det;
+ /* Invert and transpose in one go */
+ float nm00 = (m11 * m22 - m21 * m12) * s;
+ float nm01 = (m20 * m12 - m10 * m22) * s;
+ float nm02 = (m10 * m21 - m20 * m11) * s;
+ float nm10 = (m21 * m02 - m01 * m22) * s;
+ float nm11 = (m00 * m22 - m20 * m02) * s;
+ float nm12 = (m20 * m01 - m00 * m21) * s;
+ float nm20 = (m01m12 - m02m11) * s;
+ float nm21 = (m02m10 - m00m12) * s;
+ float nm22 = (m00m11 - m01m10) * s;
+ return dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link Matrix3f#set(Matrix4fc)} to set a given Matrix3f to only the upper left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see Matrix3f#set(Matrix4fc)
+ * @see #get3x3(Matrix3f)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f normal(Matrix3f dest) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix3f normalOrthonormal(Matrix3f dest) {
+ dest.set(this);
+ return dest;
+ }
+ private Matrix3f normalGeneric(Matrix3f dest) {
+ float det = (m00 * m11 - (m01 * m10)) * m22
+ + (m02 * m10 - (m00 * m12)) * m21
+ + (m01 * m12 - (m02 * m11)) * m20;
+ float s = 1.0f / det;
+ /* Invert and transpose in one go */
+ return dest._m00((m11 * m22 - m21 * m12) * s)
+ ._m01((m20 * m12 - m10 * m22) * s)
+ ._m02((m10 * m21 - m20 * m11) * s)
+ ._m10((m21 * m02 - m01 * m22) * s)
+ ._m11((m00 * m22 - m20 * m02) * s)
+ ._m12((m20 * m01 - m00 * m21) * s)
+ ._m20((m01 * m12 - m02 * m11) * s)
+ ._m21((m02 * m10 - m00 * m12) * s)
+ ._m22((m00 * m11 - m01 * m10) * s);
+ }
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal()} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @return this
+ */
+ public Matrix4f cofactor3x3() {
+ return cofactor3x3(this);
+ }
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f cofactor3x3(Matrix3f dest) {
+ return dest._m00(m11 * m22 - m21 * m12)
+ ._m01(m20 * m12 - m10 * m22)
+ ._m02(m10 * m21 - m20 * m11)
+ ._m10(m21 * m02 - m01 * m22)
+ ._m11(m00 * m22 - m20 * m02)
+ ._m12(m20 * m01 - m00 * m21)
+ ._m20(m01 * m12 - m02 * m11)
+ ._m21(m02 * m10 - m00 * m12)
+ ._m22(m00 * m11 - m01 * m10);
+ }
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f cofactor3x3(Matrix4f dest) {
+ float nm10 = m21 * m02 - m01 * m22;
+ float nm11 = m00 * m22 - m20 * m02;
+ float nm12 = m20 * m01 - m00 * m21;
+ float nm20 = m01 * m12 - m11 * m02;
+ float nm21 = m02 * m10 - m12 * m00;
+ float nm22 = m00 * m11 - m10 * m01;
+ return dest
+ ._m00(m11 * m22 - m21 * m12)
+ ._m01(m20 * m12 - m10 * m22)
+ ._m02(m10 * m21 - m20 * m11)
+ ._m03(0.0f)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(0.0f)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f)
+ ._properties((properties | PROPERTY_AFFINE) & ~(PROPERTY_TRANSLATION | PROPERTY_PERSPECTIVE));
+ }
+
+ /**
+ * Normalize the upper left 3x3 submatrix of this matrix.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @return this
+ */
+ public Matrix4f normalize3x3() {
+ return normalize3x3(this);
+ }
+
+ public Matrix4f normalize3x3(Matrix4f dest) {
+ float invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ float invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ float invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest
+ ._m00(m00 * invXlen)._m01(m01 * invXlen)._m02(m02 * invXlen)
+ ._m10(m10 * invYlen)._m11(m11 * invYlen)._m12(m12 * invYlen)
+ ._m20(m20 * invZlen)._m21(m21 * invZlen)._m22(m22 * invZlen)
+ ._m30(m30)._m31(m31)._m32(m32)._m33(m33)
+ ._properties(properties);
+ }
+
+ public Matrix3f normalize3x3(Matrix3f dest) {
+ float invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ float invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ float invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest
+ ._m00(m00 * invXlen)._m01(m01 * invXlen)._m02(m02 * invXlen)
+ ._m10(m10 * invYlen)._m11(m11 * invYlen)._m12(m12 * invYlen)
+ ._m20(m20 * invZlen)._m21(m21 * invZlen)._m22(m22 * invZlen);
+ }
+
+ public Vector4f frustumPlane(int plane, Vector4f dest) {
+ switch (plane) {
+ case PLANE_NX:
+ dest.set(m03 + m00, m13 + m10, m23 + m20, m33 + m30).normalize3();
+ break;
+ case PLANE_PX:
+ dest.set(m03 - m00, m13 - m10, m23 - m20, m33 - m30).normalize3();
+ break;
+ case PLANE_NY:
+ dest.set(m03 + m01, m13 + m11, m23 + m21, m33 + m31).normalize3();
+ break;
+ case PLANE_PY:
+ dest.set(m03 - m01, m13 - m11, m23 - m21, m33 - m31).normalize3();
+ break;
+ case PLANE_NZ:
+ dest.set(m03 + m02, m13 + m12, m23 + m22, m33 + m32).normalize3();
+ break;
+ case PLANE_PZ:
+ dest.set(m03 - m02, m13 - m12, m23 - m22, m33 - m32).normalize3();
+ break;
+ default:
+ throw new IllegalArgumentException("dest"); //$NON-NLS-1$
+ }
+ return dest;
+ }
+
+ public Vector3f frustumCorner(int corner, Vector3f point) {
+ float d1, d2, d3;
+ float n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z;
+ switch (corner) {
+ case CORNER_NXNYNZ: // left, bottom, near
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_PXNYNZ: // right, bottom, near
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_PXPYNZ: // right, top, near
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_NXPYNZ: // left, top, near
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 + m02; n3y = m13 + m12; n3z = m23 + m22; d3 = m33 + m32; // near
+ break;
+ case CORNER_PXNYPZ: // right, bottom, far
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ case CORNER_NXNYPZ: // left, bottom, far
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 + m01; n2y = m13 + m11; n2z = m23 + m21; d2 = m33 + m31; // bottom
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ case CORNER_NXPYPZ: // left, top, far
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ case CORNER_PXPYPZ: // right, top, far
+ n1x = m03 - m00; n1y = m13 - m10; n1z = m23 - m20; d1 = m33 - m30; // right
+ n2x = m03 - m01; n2y = m13 - m11; n2z = m23 - m21; d2 = m33 - m31; // top
+ n3x = m03 - m02; n3y = m13 - m12; n3z = m23 - m22; d3 = m33 - m32; // far
+ break;
+ default:
+ throw new IllegalArgumentException("corner"); //$NON-NLS-1$
+ }
+ float c23x, c23y, c23z;
+ c23x = n2y * n3z - n2z * n3y;
+ c23y = n2z * n3x - n2x * n3z;
+ c23z = n2x * n3y - n2y * n3x;
+ float c31x, c31y, c31z;
+ c31x = n3y * n1z - n3z * n1y;
+ c31y = n3z * n1x - n3x * n1z;
+ c31z = n3x * n1y - n3y * n1x;
+ float c12x, c12y, c12z;
+ c12x = n1y * n2z - n1z * n2y;
+ c12y = n1z * n2x - n1x * n2z;
+ c12z = n1x * n2y - n1y * n2x;
+ float invDot = 1.0f / (n1x * c23x + n1y * c23y + n1z * c23z);
+ point.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot;
+ point.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot;
+ point.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot;
+ return point;
+ }
+
+ /**
+ * Compute the eye/origin of the perspective frustum transformation defined by this
matrix,
+ * which can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given origin
.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(float, float, float, float) perspective()}
+ * or {@link #frustum(float, float, float, float, float, float) frustum()}.
+ *
+ * Generally, this method computes the origin in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * This method is equivalent to calling: invert(new Matrix4f()).transformProject(0, 0, -1, 0, origin)
+ * and in the case of an already available inverse of this
matrix, the method {@link #perspectiveInvOrigin(Vector3f)}
+ * on the inverse of the matrix should be used instead.
+ *
+ * Reference: http://geomalgorithms.com
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @see #perspectiveInvOrigin(Vector3f)
+ *
+ * @param origin
+ * will hold the origin of the coordinate system before applying this
+ * perspective projection transformation
+ * @return origin
+ */
+ public Vector3f perspectiveOrigin(Vector3f origin) {
+ /*
+ * Simply compute the intersection point of the left, right and top frustum plane.
+ */
+ float d1, d2, d3;
+ float n1x, n1y, n1z, n2x, n2y, n2z, n3x, n3y, n3z;
+ n1x = m03 + m00; n1y = m13 + m10; n1z = m23 + m20; d1 = m33 + m30; // left
+ n2x = m03 - m00; n2y = m13 - m10; n2z = m23 - m20; d2 = m33 - m30; // right
+ n3x = m03 - m01; n3y = m13 - m11; n3z = m23 - m21; d3 = m33 - m31; // top
+ float c23x, c23y, c23z;
+ c23x = n2y * n3z - n2z * n3y;
+ c23y = n2z * n3x - n2x * n3z;
+ c23z = n2x * n3y - n2y * n3x;
+ float c31x, c31y, c31z;
+ c31x = n3y * n1z - n3z * n1y;
+ c31y = n3z * n1x - n3x * n1z;
+ c31z = n3x * n1y - n3y * n1x;
+ float c12x, c12y, c12z;
+ c12x = n1y * n2z - n1z * n2y;
+ c12y = n1z * n2x - n1x * n2z;
+ c12z = n1x * n2y - n1y * n2x;
+ float invDot = 1.0f / (n1x * c23x + n1y * c23y + n1z * c23z);
+ origin.x = (-c23x * d1 - c31x * d2 - c12x * d3) * invDot;
+ origin.y = (-c23y * d1 - c31y * d2 - c12y * d3) * invDot;
+ origin.z = (-c23z * d1 - c31z * d2 - c12z * d3) * invDot;
+ return origin;
+ }
+
+ /**
+ * Compute the eye/origin of the inverse of the perspective frustum transformation defined by this
matrix,
+ * which can be the inverse of a projection matrix or the inverse of a combined modelview-projection matrix, and store the result
+ * in the given dest
.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(float, float, float, float) perspective()}
+ * or {@link #frustum(float, float, float, float, float, float) frustum()}.
+ *
+ * If the inverse of the modelview-projection matrix is not available, then calling {@link #perspectiveOrigin(Vector3f)}
+ * on the original modelview-projection matrix is preferred.
+ *
+ * @see #perspectiveOrigin(Vector3f)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector3f perspectiveInvOrigin(Vector3f dest) {
+ float invW = 1.0f / m23;
+ dest.x = m20 * invW;
+ dest.y = m21 * invW;
+ dest.z = m22 * invW;
+ return dest;
+ }
+
+ /**
+ * Return the vertical field-of-view angle in radians of this perspective transformation matrix.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(float, float, float, float) perspective()}
+ * or {@link #frustum(float, float, float, float, float, float) frustum()}.
+ *
+ * For orthogonal transformations this method will return 0.0
.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @return the vertical field-of-view angle in radians
+ */
+ public float perspectiveFov() {
+ /*
+ * Compute the angle between the bottom and top frustum plane normals.
+ */
+ float n1x, n1y, n1z, n2x, n2y, n2z;
+ n1x = m03 + m01; n1y = m13 + m11; n1z = m23 + m21; // bottom
+ n2x = m01 - m03; n2y = m11 - m13; n2z = m21 - m23; // top
+ float n1len = Math.sqrt(n1x * n1x + n1y * n1y + n1z * n1z);
+ float n2len = Math.sqrt(n2x * n2x + n2y * n2y + n2z * n2z);
+ return Math.acos((n1x * n2x + n1y * n2y + n1z * n2z) / (n1len * n2len));
+ }
+
+ /**
+ * Extract the near clip plane distance from this
perspective projection matrix.
+ *
+ * This method only works if this
is a perspective projection matrix, for example obtained via {@link #perspective(float, float, float, float)}.
+ *
+ * @return the near clip plane distance
+ */
+ public float perspectiveNear() {
+ return m32 / (m23 + m22);
+ }
+
+ /**
+ * Extract the far clip plane distance from this
perspective projection matrix.
+ *
+ * This method only works if this
is a perspective projection matrix, for example obtained via {@link #perspective(float, float, float, float)}.
+ *
+ * @return the far clip plane distance
+ */
+ public float perspectiveFar() {
+ return m32 / (m22 - m23);
+ }
+
+ public Vector3f frustumRayDir(float x, float y, Vector3f dir) {
+ /*
+ * This method works by first obtaining the frustum plane normals,
+ * then building the cross product to obtain the corner rays,
+ * and finally bilinearly interpolating to obtain the desired direction.
+ * The code below uses a condense form of doing all this making use
+ * of some mathematical identities to simplify the overall expression.
+ */
+ float a = m10 * m23, b = m13 * m21, c = m10 * m21, d = m11 * m23, e = m13 * m20, f = m11 * m20;
+ float g = m03 * m20, h = m01 * m23, i = m01 * m20, j = m03 * m21, k = m00 * m23, l = m00 * m21;
+ float m = m00 * m13, n = m03 * m11, o = m00 * m11, p = m01 * m13, q = m03 * m10, r = m01 * m10;
+ float m1x, m1y, m1z;
+ m1x = (d + e + f - a - b - c) * (1.0f - y) + (a - b - c + d - e + f) * y;
+ m1y = (j + k + l - g - h - i) * (1.0f - y) + (g - h - i + j - k + l) * y;
+ m1z = (p + q + r - m - n - o) * (1.0f - y) + (m - n - o + p - q + r) * y;
+ float m2x, m2y, m2z;
+ m2x = (b - c - d + e + f - a) * (1.0f - y) + (a + b - c - d - e + f) * y;
+ m2y = (h - i - j + k + l - g) * (1.0f - y) + (g + h - i - j - k + l) * y;
+ m2z = (n - o - p + q + r - m) * (1.0f - y) + (m + n - o - p - q + r) * y;
+ dir.x = m1x + (m2x - m1x) * x;
+ dir.y = m1y + (m2y - m1y) * x;
+ dir.z = m1z + (m2z - m1z) * x;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f positiveZ(Vector3f dir) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalizedPositiveZ(dir);
+ return positiveZGeneric(dir);
+ }
+ private Vector3f positiveZGeneric(Vector3f dir) {
+ return dir.set(m10 * m21 - m11 * m20, m20 * m01 - m21 * m00, m00 * m11 - m01 * m10).normalize();
+ }
+
+ public Vector3f normalizedPositiveZ(Vector3f dir) {
+ return dir.set(m02, m12, m22);
+ }
+
+ public Vector3f positiveX(Vector3f dir) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalizedPositiveX(dir);
+ return positiveXGeneric(dir);
+ }
+ private Vector3f positiveXGeneric(Vector3f dir) {
+ return dir.set(m11 * m22 - m12 * m21, m02 * m21 - m01 * m22, m01 * m12 - m02 * m11).normalize();
+ }
+
+ public Vector3f normalizedPositiveX(Vector3f dir) {
+ return dir.set(m00, m10, m20);
+ }
+
+ public Vector3f positiveY(Vector3f dir) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalizedPositiveY(dir);
+ return positiveYGeneric(dir);
+ }
+ private Vector3f positiveYGeneric(Vector3f dir) {
+ return dir.set(m12 * m20 - m10 * m22, m00 * m22 - m02 * m20, m02 * m10 - m00 * m12).normalize();
+ }
+
+ public Vector3f normalizedPositiveY(Vector3f dir) {
+ return dir.set(m01, m11, m21);
+ }
+
+ public Vector3f originAffine(Vector3f origin) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float j = m21 * m32 - m22 * m31;
+ return origin.set(-m10 * j + m11 * h - m12 * g, m00 * j - m01 * h + m02 * g, -m30 * d + m31 * b - m32 * a);
+ }
+
+ public Vector3f origin(Vector3f dest) {
+ if ((properties & PROPERTY_AFFINE) != 0)
+ return originAffine(dest);
+ return originGeneric(dest);
+ }
+ private Vector3f originGeneric(Vector3f dest) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float c = m00 * m13 - m03 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float e = m01 * m13 - m03 * m11;
+ float f = m02 * m13 - m03 * m12;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float i = m20 * m33 - m23 * m30;
+ float j = m21 * m32 - m22 * m31;
+ float k = m21 * m33 - m23 * m31;
+ float l = m22 * m33 - m23 * m32;
+ float det = a * l - b * k + c * j + d * i - e * h + f * g;
+ float invDet = 1.0f / det;
+ float nm30 = (-m10 * j + m11 * h - m12 * g) * invDet;
+ float nm31 = ( m00 * j - m01 * h + m02 * g) * invDet;
+ float nm32 = (-m30 * d + m31 * b - m32 * a) * invDet;
+ float nm33 = det / ( m20 * d - m21 * b + m22 * a);
+ return dest.set(nm30 * nm33, nm31 * nm33, nm32 * nm33);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4f shadow(Vector4f light, float a, float b, float c, float d) {
+ return shadow(light.x, light.y, light.z, light.w, a, b, c, d, this);
+ }
+
+ public Matrix4f shadow(Vector4f light, float a, float b, float c, float d, Matrix4f dest) {
+ return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4f shadow(float lightX, float lightY, float lightZ, float lightW, float a, float b, float c, float d) {
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this);
+ }
+
+ public Matrix4f shadow(float lightX, float lightY, float lightZ, float lightW, float a, float b, float c, float d, Matrix4f dest) {
+ // normalize plane
+ float invPlaneLen = Math.invsqrt(a*a + b*b + c*c);
+ float an = a * invPlaneLen;
+ float bn = b * invPlaneLen;
+ float cn = c * invPlaneLen;
+ float dn = d * invPlaneLen;
+
+ float dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW;
+
+ // compute right matrix elements
+ float rm00 = dot - an * lightX;
+ float rm01 = -an * lightY;
+ float rm02 = -an * lightZ;
+ float rm03 = -an * lightW;
+ float rm10 = -bn * lightX;
+ float rm11 = dot - bn * lightY;
+ float rm12 = -bn * lightZ;
+ float rm13 = -bn * lightW;
+ float rm20 = -cn * lightX;
+ float rm21 = -cn * lightY;
+ float rm22 = dot - cn * lightZ;
+ float rm23 = -cn * lightW;
+ float rm30 = -dn * lightX;
+ float rm31 = -dn * lightY;
+ float rm32 = -dn * lightZ;
+ float rm33 = dot - dn * lightW;
+
+ // matrix multiplication
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03;
+ float nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02 + m33 * rm03;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13;
+ float nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12 + m33 * rm13;
+ float nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23;
+ float nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23;
+ float nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23;
+ float nm23 = m03 * rm20 + m13 * rm21 + m23 * rm22 + m33 * rm23;
+ dest._m30(m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33)
+ ._m31(m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33)
+ ._m32(m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33)
+ ._m33(m03 * rm30 + m13 * rm31 + m23 * rm32 + m33 * rm33)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ public Matrix4f shadow(Vector4f light, Matrix4fc planeTransform, Matrix4f dest) {
+ // compute plane equation by transforming (y = 0)
+ float a = planeTransform.m10();
+ float b = planeTransform.m11();
+ float c = planeTransform.m12();
+ float d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(light.x, light.y, light.z, light.w, a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4f shadow(Vector4f light, Matrix4f planeTransform) {
+ return shadow(light, planeTransform, this);
+ }
+
+ public Matrix4f shadow(float lightX, float lightY, float lightZ, float lightW, Matrix4fc planeTransform, Matrix4f dest) {
+ // compute plane equation by transforming (y = 0)
+ float a = planeTransform.m10();
+ float b = planeTransform.m11();
+ float c = planeTransform.m12();
+ float d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4f shadow(float lightX, float lightY, float lightZ, float lightW, Matrix4f planeTransform) {
+ return shadow(lightX, lightY, lightZ, lightW, planeTransform, this);
+ }
+
+ /**
+ * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
while constraining a cylindrical rotation around the given up
vector.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the rotation axis (must be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4f billboardCylindrical(Vector3fc objPos, Vector3fc targetPos, Vector3fc up) {
+ float dirX = targetPos.x() - objPos.x();
+ float dirY = targetPos.y() - objPos.y();
+ float dirZ = targetPos.z() - objPos.z();
+ // left = up x dir
+ float leftX = up.y() * dirZ - up.z() * dirY;
+ float leftY = up.z() * dirX - up.x() * dirZ;
+ float leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ float invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // recompute dir by constraining rotation around 'up'
+ // dir = left x up
+ dirX = leftY * up.z() - leftZ * up.y();
+ dirY = leftZ * up.x() - leftX * up.z();
+ dirZ = leftX * up.y() - leftY * up.x();
+ // normalize dir
+ float invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // set matrix elements
+ this._m00(leftX)
+ ._m01(leftY)
+ ._m02(leftZ)
+ ._m03(0.0f)
+ ._m10(up.x())
+ ._m11(up.y())
+ ._m12(up.z())
+ ._m13(0.0f)
+ ._m20(dirX)
+ ._m21(dirY)
+ ._m22(dirZ)
+ ._m23(0.0f)
+ ._m30(objPos.x())
+ ._m31(objPos.y())
+ ._m32(objPos.z())
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * If preserving an up vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained
+ * using {@link #billboardSpherical(Vector3fc, Vector3fc)}.
+ *
+ * @see #billboardSpherical(Vector3fc, Vector3fc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the up axis used to orient the object
+ * @return this
+ */
+ public Matrix4f billboardSpherical(Vector3fc objPos, Vector3fc targetPos, Vector3fc up) {
+ float dirX = targetPos.x() - objPos.x();
+ float dirY = targetPos.y() - objPos.y();
+ float dirZ = targetPos.z() - objPos.z();
+ // normalize dir
+ float invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // left = up x dir
+ float leftX = up.y() * dirZ - up.z() * dirY;
+ float leftY = up.z() * dirX - up.x() * dirZ;
+ float leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ float invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // up = dir x left
+ float upX = dirY * leftZ - dirZ * leftY;
+ float upY = dirZ * leftX - dirX * leftZ;
+ float upZ = dirX * leftY - dirY * leftX;
+ // set matrix elements
+ this._m00(leftX)
+ ._m01(leftY)
+ ._m02(leftZ)
+ ._m03(0.0f)
+ ._m10(upX)
+ ._m11(upY)
+ ._m12(upZ)
+ ._m13(0.0f)
+ ._m20(dirX)
+ ._m21(dirY)
+ ._m22(dirZ)
+ ._m23(0.0f)
+ ._m30(objPos.x())
+ ._m31(objPos.y())
+ ._m32(objPos.z())
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
using a shortest arc rotation by not preserving any up vector of the object.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * In order to specify an up vector which needs to be maintained when rotating the +Z axis of the object,
+ * use {@link #billboardSpherical(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #billboardSpherical(Vector3fc, Vector3fc, Vector3fc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @return this
+ */
+ public Matrix4f billboardSpherical(Vector3fc objPos, Vector3fc targetPos) {
+ float toDirX = targetPos.x() - objPos.x();
+ float toDirY = targetPos.y() - objPos.y();
+ float toDirZ = targetPos.z() - objPos.z();
+ float x = -toDirY;
+ float y = toDirX;
+ float w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ;
+ float invNorm = Math.invsqrt(x * x + y * y + w * w);
+ x *= invNorm;
+ y *= invNorm;
+ w *= invNorm;
+ float q00 = (x + x) * x;
+ float q11 = (y + y) * y;
+ float q01 = (x + x) * y;
+ float q03 = (x + x) * w;
+ float q13 = (y + y) * w;
+ this._m00(1.0f - q11)
+ ._m01(q01)
+ ._m02(-q13)
+ ._m03(0.0f)
+ ._m10(q01)
+ ._m11(1.0f - q00)
+ ._m12(q03)
+ ._m13(0.0f)
+ ._m20(q13)
+ ._m21(-q03)
+ ._m22(1.0f - q11 - q00)
+ ._m23(0.0f)
+ ._m30(objPos.x())
+ ._m31(objPos.y())
+ ._m32(objPos.z())
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(m00);
+ result = prime * result + Float.floatToIntBits(m01);
+ result = prime * result + Float.floatToIntBits(m02);
+ result = prime * result + Float.floatToIntBits(m03);
+ result = prime * result + Float.floatToIntBits(m10);
+ result = prime * result + Float.floatToIntBits(m11);
+ result = prime * result + Float.floatToIntBits(m12);
+ result = prime * result + Float.floatToIntBits(m13);
+ result = prime * result + Float.floatToIntBits(m20);
+ result = prime * result + Float.floatToIntBits(m21);
+ result = prime * result + Float.floatToIntBits(m22);
+ result = prime * result + Float.floatToIntBits(m23);
+ result = prime * result + Float.floatToIntBits(m30);
+ result = prime * result + Float.floatToIntBits(m31);
+ result = prime * result + Float.floatToIntBits(m32);
+ result = prime * result + Float.floatToIntBits(m33);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof Matrix4f))
+ return false;
+ Matrix4fc other = (Matrix4fc) obj;
+ if (Float.floatToIntBits(m00) != Float.floatToIntBits(other.m00()))
+ return false;
+ if (Float.floatToIntBits(m01) != Float.floatToIntBits(other.m01()))
+ return false;
+ if (Float.floatToIntBits(m02) != Float.floatToIntBits(other.m02()))
+ return false;
+ if (Float.floatToIntBits(m03) != Float.floatToIntBits(other.m03()))
+ return false;
+ if (Float.floatToIntBits(m10) != Float.floatToIntBits(other.m10()))
+ return false;
+ if (Float.floatToIntBits(m11) != Float.floatToIntBits(other.m11()))
+ return false;
+ if (Float.floatToIntBits(m12) != Float.floatToIntBits(other.m12()))
+ return false;
+ if (Float.floatToIntBits(m13) != Float.floatToIntBits(other.m13()))
+ return false;
+ if (Float.floatToIntBits(m20) != Float.floatToIntBits(other.m20()))
+ return false;
+ if (Float.floatToIntBits(m21) != Float.floatToIntBits(other.m21()))
+ return false;
+ if (Float.floatToIntBits(m22) != Float.floatToIntBits(other.m22()))
+ return false;
+ if (Float.floatToIntBits(m23) != Float.floatToIntBits(other.m23()))
+ return false;
+ if (Float.floatToIntBits(m30) != Float.floatToIntBits(other.m30()))
+ return false;
+ if (Float.floatToIntBits(m31) != Float.floatToIntBits(other.m31()))
+ return false;
+ if (Float.floatToIntBits(m32) != Float.floatToIntBits(other.m32()))
+ return false;
+ if (Float.floatToIntBits(m33) != Float.floatToIntBits(other.m33()))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix4fc m, float delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix4f))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m02, m.m02(), delta))
+ return false;
+ if (!Runtime.equals(m03, m.m03(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m12, m.m12(), delta))
+ return false;
+ if (!Runtime.equals(m13, m.m13(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ if (!Runtime.equals(m22, m.m22(), delta))
+ return false;
+ if (!Runtime.equals(m23, m.m23(), delta))
+ return false;
+ if (!Runtime.equals(m30, m.m30(), delta))
+ return false;
+ if (!Runtime.equals(m31, m.m31(), delta))
+ return false;
+ if (!Runtime.equals(m32, m.m32(), delta))
+ return false;
+ if (!Runtime.equals(m33, m.m33(), delta))
+ return false;
+ return true;
+ }
+
+ public Matrix4f pick(float x, float y, float width, float height, int[] viewport, Matrix4f dest) {
+ float sx = viewport[2] / width;
+ float sy = viewport[3] / height;
+ float tx = (viewport[2] + 2.0f * (viewport[0] - x)) / width;
+ float ty = (viewport[3] + 2.0f * (viewport[1] - y)) / height;
+ dest._m30(m00 * tx + m10 * ty + m30)
+ ._m31(m01 * tx + m11 * ty + m31)
+ ._m32(m02 * tx + m12 * ty + m32)
+ ._m33(m03 * tx + m13 * ty + m33)
+ ._m00(m00 * sx)
+ ._m01(m01 * sx)
+ ._m02(m02 * sx)
+ ._m03(m03 * sx)
+ ._m10(m10 * sy)
+ ._m11(m11 * sy)
+ ._m12(m12 * sy)
+ ._m13(m13 * sy)
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @return this
+ */
+ public Matrix4f pick(float x, float y, float width, float height, int[] viewport) {
+ return pick(x, y, width, height, viewport, this);
+ }
+
+ public boolean isAffine() {
+ return m03 == 0.0f && m13 == 0.0f && m23 == 0.0f && m33 == 1.0f;
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix4f swap(Matrix4f other) {
+ MemUtil.INSTANCE.swap(this, other);
+ int props = properties;
+ this.properties = other.properties();
+ other.properties = props;
+ return this;
+ }
+
+ public Matrix4f arcball(float radius, float centerX, float centerY, float centerZ, float angleX, float angleY, Matrix4f dest) {
+ float m30 = m20 * -radius + this.m30;
+ float m31 = m21 * -radius + this.m31;
+ float m32 = m22 * -radius + this.m32;
+ float m33 = m23 * -radius + this.m33;
+ float sin = Math.sin(angleX);
+ float cos = Math.cosFromSin(sin, angleX);
+ float nm10 = m10 * cos + m20 * sin;
+ float nm11 = m11 * cos + m21 * sin;
+ float nm12 = m12 * cos + m22 * sin;
+ float nm13 = m13 * cos + m23 * sin;
+ float m20 = this.m20 * cos - m10 * sin;
+ float m21 = this.m21 * cos - m11 * sin;
+ float m22 = this.m22 * cos - m12 * sin;
+ float m23 = this.m23 * cos - m13 * sin;
+ sin = Math.sin(angleY);
+ cos = Math.cosFromSin(sin, angleY);
+ float nm00 = m00 * cos - m20 * sin;
+ float nm01 = m01 * cos - m21 * sin;
+ float nm02 = m02 * cos - m22 * sin;
+ float nm03 = m03 * cos - m23 * sin;
+ float nm20 = m00 * sin + m20 * cos;
+ float nm21 = m01 * sin + m21 * cos;
+ float nm22 = m02 * sin + m22 * cos;
+ float nm23 = m03 * sin + m23 * cos;
+ dest._m30(-nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30)
+ ._m31(-nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31)
+ ._m32(-nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32)
+ ._m33(-nm03 * centerX - nm13 * centerY - nm23 * centerZ + m33)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m23(nm23)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ public Matrix4f arcball(float radius, Vector3fc center, float angleX, float angleY, Matrix4f dest) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, dest);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4f arcball(float radius, float centerX, float centerY, float centerZ, float angleX, float angleY) {
+ return arcball(radius, centerX, centerY, centerZ, angleX, angleY, this);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4f arcball(float radius, Vector3fc center, float angleX, float angleY) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, this);
+ }
+
+ /**
+ * Compute the axis-aligned bounding box of the frustum described by this
matrix and store the minimum corner
+ * coordinates in the given min
and the maximum corner coordinates in the given max
vector.
+ *
+ * The matrix this
is assumed to be the {@link #invert() inverse} of the origial view-projection matrix
+ * for which to compute the axis-aligned bounding box in world-space.
+ *
+ * The axis-aligned bounding box of the unit frustum is (-1, -1, -1)
, (1, 1, 1)
.
+ *
+ * @param min
+ * will hold the minimum corner coordinates of the axis-aligned bounding box
+ * @param max
+ * will hold the maximum corner coordinates of the axis-aligned bounding box
+ * @return this
+ */
+ public Matrix4f frustumAabb(Vector3f min, Vector3f max) {
+ float minX = Float.POSITIVE_INFINITY;
+ float minY = Float.POSITIVE_INFINITY;
+ float minZ = Float.POSITIVE_INFINITY;
+ float maxX = Float.NEGATIVE_INFINITY;
+ float maxY = Float.NEGATIVE_INFINITY;
+ float maxZ = Float.NEGATIVE_INFINITY;
+ for (int t = 0; t < 8; t++) {
+ float x = ((t & 1) << 1) - 1.0f;
+ float y = (((t >>> 1) & 1) << 1) - 1.0f;
+ float z = (((t >>> 2) & 1) << 1) - 1.0f;
+ float invW = 1.0f / (m03 * x + m13 * y + m23 * z + m33);
+ float nx = (m00 * x + m10 * y + m20 * z + m30) * invW;
+ float ny = (m01 * x + m11 * y + m21 * z + m31) * invW;
+ float nz = (m02 * x + m12 * y + m22 * z + m32) * invW;
+ minX = minX < nx ? minX : nx;
+ minY = minY < ny ? minY : ny;
+ minZ = minZ < nz ? minZ : nz;
+ maxX = maxX > nx ? maxX : nx;
+ maxY = maxY > ny ? maxY : ny;
+ maxZ = maxZ > nz ? maxZ : nz;
+ }
+ min.x = minX;
+ min.y = minY;
+ min.z = minZ;
+ max.x = maxX;
+ max.y = maxY;
+ max.z = maxZ;
+ return this;
+ }
+
+ public Matrix4f projectedGridRange(Matrix4fc projector, float sLower, float sUpper, Matrix4f dest) {
+ // Compute intersection with frustum edges and plane
+ float minX = Float.POSITIVE_INFINITY, minY = Float.POSITIVE_INFINITY;
+ float maxX = Float.NEGATIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
+ boolean intersection = false;
+ for (int t = 0; t < 3 * 4; t++) {
+ float c0X, c0Y, c0Z;
+ float c1X, c1Y, c1Z;
+ if (t < 4) {
+ // all x edges
+ c0X = -1; c1X = +1;
+ c0Y = c1Y = ((t & 1) << 1) - 1.0f;
+ c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0f;
+ } else if (t < 8) {
+ // all y edges
+ c0Y = -1; c1Y = +1;
+ c0X = c1X = ((t & 1) << 1) - 1.0f;
+ c0Z = c1Z = (((t >>> 1) & 1) << 1) - 1.0f;
+ } else {
+ // all z edges
+ c0Z = -1; c1Z = +1;
+ c0X = c1X = ((t & 1) << 1) - 1.0f;
+ c0Y = c1Y = (((t >>> 1) & 1) << 1) - 1.0f;
+ }
+ // unproject corners
+ float invW = 1.0f / (m03 * c0X + m13 * c0Y + m23 * c0Z + m33);
+ float p0x = (m00 * c0X + m10 * c0Y + m20 * c0Z + m30) * invW;
+ float p0y = (m01 * c0X + m11 * c0Y + m21 * c0Z + m31) * invW;
+ float p0z = (m02 * c0X + m12 * c0Y + m22 * c0Z + m32) * invW;
+ invW = 1.0f / (m03 * c1X + m13 * c1Y + m23 * c1Z + m33);
+ float p1x = (m00 * c1X + m10 * c1Y + m20 * c1Z + m30) * invW;
+ float p1y = (m01 * c1X + m11 * c1Y + m21 * c1Z + m31) * invW;
+ float p1z = (m02 * c1X + m12 * c1Y + m22 * c1Z + m32) * invW;
+ float dirX = p1x - p0x;
+ float dirY = p1y - p0y;
+ float dirZ = p1z - p0z;
+ float invDenom = 1.0f / dirY;
+ // test for intersection
+ for (int s = 0; s < 2; s++) {
+ float isectT = -(p0y + (s == 0 ? sLower : sUpper)) * invDenom;
+ if (isectT >= 0.0f && isectT <= 1.0f) {
+ intersection = true;
+ // project with projector matrix
+ float ix = p0x + isectT * dirX;
+ float iz = p0z + isectT * dirZ;
+ invW = 1.0f / (projector.m03() * ix + projector.m23() * iz + projector.m33());
+ float px = (projector.m00() * ix + projector.m20() * iz + projector.m30()) * invW;
+ float py = (projector.m01() * ix + projector.m21() * iz + projector.m31()) * invW;
+ minX = minX < px ? minX : px;
+ minY = minY < py ? minY : py;
+ maxX = maxX > px ? maxX : px;
+ maxY = maxY > py ? maxY : py;
+ }
+ }
+ }
+ if (!intersection)
+ return null; // <- projected grid is not visible
+ dest.set(maxX - minX, 0, 0, 0, 0, maxY - minY, 0, 0, 0, 0, 1, 0, minX, minY, 0, 1);
+ dest._properties(PROPERTY_AFFINE);
+ return dest;
+ }
+
+ /**
+ * Change the near and far clip plane distances of this
perspective frustum transformation matrix
+ * and store the result in dest
.
+ *
+ * This method only works if this
is a perspective projection frustum transformation, for example obtained
+ * via {@link #perspective(float, float, float, float) perspective()} or {@link #frustum(float, float, float, float, float, float) frustum()}.
+ *
+ * @see #perspective(float, float, float, float)
+ * @see #frustum(float, float, float, float, float, float)
+ *
+ * @param near
+ * the new near clip plane distance
+ * @param far
+ * the new far clip plane distance
+ * @param dest
+ * will hold the resulting matrix
+ * @return dest
+ */
+ public Matrix4f perspectiveFrustumSlice(float near, float far, Matrix4f dest) {
+ float invOldNear = (m23 + m22) / m32;
+ float invNearFar = 1.0f / (near - far);
+ dest._m00(m00 * invOldNear * near)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(m11 * invOldNear * near)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(m20)
+ ._m21(m21)
+ ._m22((far + near) * invNearFar)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32((far + far) * near * invNearFar)
+ ._m33(m33)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL));
+ return dest;
+ }
+
+ /**
+ * Build an ortographic projection transformation that fits the view-projection transformation represented by this
+ * into the given affine view
transformation.
+ *
+ * The transformation represented by this
must be given as the {@link #invert() inverse} of a typical combined camera view-projection
+ * transformation, whose projection can be either orthographic or perspective.
+ *
+ * The view
must be an {@link #isAffine() affine} transformation which in the application of Cascaded Shadow Maps is usually the light view transformation.
+ * It be obtained via any affine transformation or for example via {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()}.
+ *
+ * Reference: OpenGL SDK - Cascaded Shadow Maps
+ *
+ * @param view
+ * the view transformation to build a corresponding orthographic projection to fit the frustum of this
+ * @param dest
+ * will hold the crop projection transformation
+ * @return dest
+ */
+ public Matrix4f orthoCrop(Matrix4fc view, Matrix4f dest) {
+ // determine min/max world z and min/max orthographically view-projected x/y
+ float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY;
+ float minY = Float.POSITIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
+ float minZ = Float.POSITIVE_INFINITY, maxZ = Float.NEGATIVE_INFINITY;
+ for (int t = 0; t < 8; t++) {
+ float x = ((t & 1) << 1) - 1.0f;
+ float y = (((t >>> 1) & 1) << 1) - 1.0f;
+ float z = (((t >>> 2) & 1) << 1) - 1.0f;
+ float invW = 1.0f / (m03 * x + m13 * y + m23 * z + m33);
+ float wx = (m00 * x + m10 * y + m20 * z + m30) * invW;
+ float wy = (m01 * x + m11 * y + m21 * z + m31) * invW;
+ float wz = (m02 * x + m12 * y + m22 * z + m32) * invW;
+ invW = 1.0f / (view.m03() * wx + view.m13() * wy + view.m23() * wz + view.m33());
+ float vx = view.m00() * wx + view.m10() * wy + view.m20() * wz + view.m30();
+ float vy = view.m01() * wx + view.m11() * wy + view.m21() * wz + view.m31();
+ float vz = (view.m02() * wx + view.m12() * wy + view.m22() * wz + view.m32()) * invW;
+ minX = minX < vx ? minX : vx;
+ maxX = maxX > vx ? maxX : vx;
+ minY = minY < vy ? minY : vy;
+ maxY = maxY > vy ? maxY : vy;
+ minZ = minZ < vz ? minZ : vz;
+ maxZ = maxZ > vz ? maxZ : vz;
+ }
+ // build crop projection matrix to fit 'this' frustum into view
+ return dest.setOrtho(minX, maxX, minY, maxY, -maxZ, -minZ);
+ }
+
+ /**
+ * Set this
matrix to a perspective transformation that maps the trapezoid spanned by the four corner coordinates
+ * (p0x, p0y)
, (p1x, p1y)
, (p2x, p2y)
and (p3x, p3y)
to the unit square [(-1, -1)..(+1, +1)]
.
+ *
+ * The corner coordinates are given in counter-clockwise order starting from the left corner on the smaller parallel side of the trapezoid
+ * seen when looking at the trapezoid oriented with its shorter parallel edge at the bottom and its longer parallel edge at the top.
+ *
+ * Reference: Trapezoidal Shadow Maps (TSM) - Recipe
+ *
+ * @param p0x
+ * the x coordinate of the left corner at the shorter edge of the trapezoid
+ * @param p0y
+ * the y coordinate of the left corner at the shorter edge of the trapezoid
+ * @param p1x
+ * the x coordinate of the right corner at the shorter edge of the trapezoid
+ * @param p1y
+ * the y coordinate of the right corner at the shorter edge of the trapezoid
+ * @param p2x
+ * the x coordinate of the right corner at the longer edge of the trapezoid
+ * @param p2y
+ * the y coordinate of the right corner at the longer edge of the trapezoid
+ * @param p3x
+ * the x coordinate of the left corner at the longer edge of the trapezoid
+ * @param p3y
+ * the y coordinate of the left corner at the longer edge of the trapezoid
+ * @return this
+ */
+ public Matrix4f trapezoidCrop(float p0x, float p0y, float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
+ float aX = p1y - p0y, aY = p0x - p1x;
+ float nm00 = aY;
+ float nm10 = -aX;
+ float nm30 = aX * p0y - aY * p0x;
+ float nm01 = aX;
+ float nm11 = aY;
+ float nm31 = -(aX * p0x + aY * p0y);
+ float c3x = nm00 * p3x + nm10 * p3y + nm30;
+ float c3y = nm01 * p3x + nm11 * p3y + nm31;
+ float s = -c3x / c3y;
+ nm00 += s * nm01;
+ nm10 += s * nm11;
+ nm30 += s * nm31;
+ float d1x = nm00 * p1x + nm10 * p1y + nm30;
+ float d2x = nm00 * p2x + nm10 * p2y + nm30;
+ float d = d1x * c3y / (d2x - d1x);
+ nm31 += d;
+ float sx = 2.0f / d2x;
+ float sy = 1.0f / (c3y + d);
+ float u = (sy + sy) * d / (1.0f - sy * d);
+ float m03 = nm01 * sy;
+ float m13 = nm11 * sy;
+ float m33 = nm31 * sy;
+ nm01 = (u + 1.0f) * m03;
+ nm11 = (u + 1.0f) * m13;
+ nm31 = (u + 1.0f) * m33 - u;
+ nm00 = sx * nm00 - m03;
+ nm10 = sx * nm10 - m13;
+ nm30 = sx * nm30 - m33;
+ set(nm00, nm01, 0, m03,
+ nm10, nm11, 0, m13,
+ 0, 0, 1, 0,
+ nm30, nm31, 0, m33);
+ _properties(0);
+ return this;
+ }
+
+ public Matrix4f transformAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Vector3f outMin, Vector3f outMax) {
+ float xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX;
+ float xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX;
+ float yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY;
+ float ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY;
+ float zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ;
+ float zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ;
+ float xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz;
+ float xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz;
+ if (xax < xbx) {
+ xminx = xax;
+ xmaxx = xbx;
+ } else {
+ xminx = xbx;
+ xmaxx = xax;
+ }
+ if (xay < xby) {
+ xminy = xay;
+ xmaxy = xby;
+ } else {
+ xminy = xby;
+ xmaxy = xay;
+ }
+ if (xaz < xbz) {
+ xminz = xaz;
+ xmaxz = xbz;
+ } else {
+ xminz = xbz;
+ xmaxz = xaz;
+ }
+ if (yax < ybx) {
+ yminx = yax;
+ ymaxx = ybx;
+ } else {
+ yminx = ybx;
+ ymaxx = yax;
+ }
+ if (yay < yby) {
+ yminy = yay;
+ ymaxy = yby;
+ } else {
+ yminy = yby;
+ ymaxy = yay;
+ }
+ if (yaz < ybz) {
+ yminz = yaz;
+ ymaxz = ybz;
+ } else {
+ yminz = ybz;
+ ymaxz = yaz;
+ }
+ if (zax < zbx) {
+ zminx = zax;
+ zmaxx = zbx;
+ } else {
+ zminx = zbx;
+ zmaxx = zax;
+ }
+ if (zay < zby) {
+ zminy = zay;
+ zmaxy = zby;
+ } else {
+ zminy = zby;
+ zmaxy = zay;
+ }
+ if (zaz < zbz) {
+ zminz = zaz;
+ zmaxz = zbz;
+ } else {
+ zminz = zbz;
+ zmaxz = zaz;
+ }
+ outMin.x = xminx + yminx + zminx + m30;
+ outMin.y = xminy + yminy + zminy + m31;
+ outMin.z = xminz + yminz + zminz + m32;
+ outMax.x = xmaxx + ymaxx + zmaxx + m30;
+ outMax.y = xmaxy + ymaxy + zmaxy + m31;
+ outMax.z = xmaxz + ymaxz + zmaxz + m32;
+ return this;
+ }
+
+ public Matrix4f transformAab(Vector3fc min, Vector3fc max, Vector3f outMin, Vector3f outMax) {
+ return transformAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), outMin, outMax);
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix4f lerp(Matrix4fc other, float t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix4f lerp(Matrix4fc other, float t, Matrix4f dest) {
+ dest._m00(Math.fma(other.m00() - m00, t, m00))
+ ._m01(Math.fma(other.m01() - m01, t, m01))
+ ._m02(Math.fma(other.m02() - m02, t, m02))
+ ._m03(Math.fma(other.m03() - m03, t, m03))
+ ._m10(Math.fma(other.m10() - m10, t, m10))
+ ._m11(Math.fma(other.m11() - m11, t, m11))
+ ._m12(Math.fma(other.m12() - m12, t, m12))
+ ._m13(Math.fma(other.m13() - m13, t, m13))
+ ._m20(Math.fma(other.m20() - m20, t, m20))
+ ._m21(Math.fma(other.m21() - m21, t, m21))
+ ._m22(Math.fma(other.m22() - m22, t, m22))
+ ._m23(Math.fma(other.m23() - m23, t, m23))
+ ._m30(Math.fma(other.m30() - m30, t, m30))
+ ._m31(Math.fma(other.m31() - m31, t, m31))
+ ._m32(Math.fma(other.m32() - m32, t, m32))
+ ._m33(Math.fma(other.m33() - m33, t, m33))
+ ._properties(properties & other.properties());
+ return dest;
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4f().lookAt(new Vector3f(), new Vector3f(dir).negate(), up).invertAffine(), dest)
+ *
+ * @see #rotateTowards(float, float, float, float, float, float, Matrix4f)
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateTowards(Vector3fc dir, Vector3fc up, Matrix4f dest) {
+ return rotateTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4f().lookAt(new Vector3f(), new Vector3f(dir).negate(), up).invertAffine())
+ *
+ * @see #rotateTowards(float, float, float, float, float, float)
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction to orient towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4f rotateTowards(Vector3fc dir, Vector3fc up) {
+ return rotateTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4f().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine())
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4f().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4f dest) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ float rm00 = leftX;
+ float rm01 = leftY;
+ float rm02 = leftZ;
+ float rm10 = upnX;
+ float rm11 = upnY;
+ float rm12 = upnZ;
+ float rm20 = ndirX;
+ float rm21 = ndirY;
+ float rm22 = ndirZ;
+ dest._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33);
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm03 = m03 * rm00 + m13 * rm01 + m23 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ float nm13 = m03 * rm10 + m13 * rm11 + m23 * rm12;
+ dest._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m23(m03 * rm20 + m13 * rm21 + m23 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m03(nm03)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m13(nm13)
+ ._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with dir
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(new Vector3f(), new Vector3f(dir).negate(), up).invertAffine()
+ *
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ * @see #rotateTowards(float, float, float, float, float, float)
+ *
+ * @param dir
+ * the direction to orient the local -z axis towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4f rotationTowards(Vector3fc dir, Vector3fc up) {
+ return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with (dirX, dirY, dirZ)
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine()
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f rotationTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ this._m00(leftX)
+ ._m01(leftY)
+ ._m02(leftZ)
+ ._m10(upnX)
+ ._m11(upnY)
+ ._m12(upnZ)
+ ._m20(ndirX)
+ ._m21(ndirY)
+ ._m22(ndirZ)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given pos
and aligns the local -z
+ * axis with dir
.
+ *
+ * This method is equivalent to calling: translation(pos).rotateTowards(dir, up)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ *
+ * @param pos
+ * the position to translate to
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4f translationRotateTowards(Vector3fc pos, Vector3fc dir, Vector3fc up) {
+ return translationRotateTowards(pos.x(), pos.y(), pos.z(), dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given (posX, posY, posZ)
and aligns the local -z
+ * axis with (dirX, dirY, dirZ)
.
+ *
+ * This method is equivalent to calling: translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotateTowards(float, float, float, float, float, float)
+ *
+ * @param posX
+ * the x-coordinate of the position to translate to
+ * @param posY
+ * the y-coordinate of the position to translate to
+ * @param posZ
+ * the z-coordinate of the position to translate to
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f translationRotateTowards(float posX, float posY, float posZ, float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ this._m00(leftX)
+ ._m01(leftY)
+ ._m02(leftZ)
+ ._m03(0.0f)
+ ._m10(upnX)
+ ._m11(upnY)
+ ._m12(upnZ)
+ ._m13(0.0f)
+ ._m20(ndirX)
+ ._m21(ndirY)
+ ._m22(ndirZ)
+ ._m23(0.0f)
+ ._m30(posX)
+ ._m31(posY)
+ ._m32(posZ)
+ ._m33(1.0f)
+ ._properties(PROPERTY_AFFINE | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ public Vector3f getEulerAnglesZYX(Vector3f dest) {
+ dest.x = Math.atan2(m12, m22);
+ dest.y = Math.atan2(-m02, Math.sqrt(1.0f - m02 * m02));
+ dest.z = Math.atan2(m01, m00);
+ return dest;
+ }
+
+ public Vector3f getEulerAnglesXYZ(Vector3f dest) {
+ dest.x = Math.atan2(-m21, m22);
+ dest.y = Math.atan2(m20, Math.sqrt(1.0f - m20 * m20));
+ dest.z = Math.atan2(-m10, m00);
+ return dest;
+ }
+
+ /**
+ * Compute the extents of the coordinate system before this {@link #isAffine() affine} transformation was applied
+ * and store the resulting corner coordinates in corner
and the span vectors in
+ * xDir
, yDir
and zDir
.
+ *
+ * That means, given the maximum extents of the coordinate system between [-1..+1]
in all dimensions,
+ * this method returns one corner and the length and direction of the three base axis vectors in the coordinate
+ * system before this transformation is applied, which transforms into the corner coordinates [-1, +1]
.
+ *
+ * This method is equivalent to computing at least three adjacent corners using {@link #frustumCorner(int, Vector3f)}
+ * and subtracting them to obtain the length and direction of the span vectors.
+ *
+ * @param corner
+ * will hold one corner of the span (usually the corner {@link Matrix4fc#CORNER_NXNYNZ})
+ * @param xDir
+ * will hold the direction and length of the span along the positive X axis
+ * @param yDir
+ * will hold the direction and length of the span along the positive Y axis
+ * @param zDir
+ * will hold the direction and length of the span along the positive z axis
+ * @return this
+ */
+ public Matrix4f affineSpan(Vector3f corner, Vector3f xDir, Vector3f yDir, Vector3f zDir) {
+ float a = m10 * m22, b = m10 * m21, c = m10 * m02, d = m10 * m01;
+ float e = m11 * m22, f = m11 * m20, g = m11 * m02, h = m11 * m00;
+ float i = m12 * m21, j = m12 * m20, k = m12 * m01, l = m12 * m00;
+ float m = m20 * m02, n = m20 * m01, o = m21 * m02, p = m21 * m00;
+ float q = m22 * m01, r = m22 * m00;
+ float s = 1.0f / (m00 * m11 - m01 * m10) * m22 + (m02 * m10 - m00 * m12) * m21 + (m01 * m12 - m02 * m11) * m20;
+ float nm00 = (e - i) * s, nm01 = (o - q) * s, nm02 = (k - g) * s;
+ float nm10 = (j - a) * s, nm11 = (r - m) * s, nm12 = (c - l) * s;
+ float nm20 = (b - f) * s, nm21 = (n - p) * s, nm22 = (h - d) * s;
+ corner.x = -nm00 - nm10 - nm20 + (a * m31 - b * m32 + f * m32 - e * m30 + i * m30 - j * m31) * s;
+ corner.y = -nm01 - nm11 - nm21 + (m * m31 - n * m32 + p * m32 - o * m30 + q * m30 - r * m31) * s;
+ corner.z = -nm02 - nm12 - nm22 + (g * m30 - k * m30 + l * m31 - c * m31 + d * m32 - h * m32) * s;
+ xDir.x = 2.0f * nm00; xDir.y = 2.0f * nm01; xDir.z = 2.0f * nm02;
+ yDir.x = 2.0f * nm10; yDir.y = 2.0f * nm11; yDir.z = 2.0f * nm12;
+ zDir.x = 2.0f * nm20; zDir.y = 2.0f * nm21; zDir.z = 2.0f * nm22;
+ return this;
+ }
+
+ public boolean testPoint(float x, float y, float z) {
+ float nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30;
+ float pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30;
+ float nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31;
+ float pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31;
+ float nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32;
+ float pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32;
+ return nxX * x + nxY * y + nxZ * z + nxW >= 0 && pxX * x + pxY * y + pxZ * z + pxW >= 0 &&
+ nyX * x + nyY * y + nyZ * z + nyW >= 0 && pyX * x + pyY * y + pyZ * z + pyW >= 0 &&
+ nzX * x + nzY * y + nzZ * z + nzW >= 0 && pzX * x + pzY * y + pzZ * z + pzW >= 0;
+ }
+
+ public boolean testSphere(float x, float y, float z, float r) {
+ float invl;
+ float nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30;
+ invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ);
+ nxX *= invl; nxY *= invl; nxZ *= invl; nxW *= invl;
+ float pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30;
+ invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ);
+ pxX *= invl; pxY *= invl; pxZ *= invl; pxW *= invl;
+ float nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31;
+ invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ);
+ nyX *= invl; nyY *= invl; nyZ *= invl; nyW *= invl;
+ float pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31;
+ invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ);
+ pyX *= invl; pyY *= invl; pyZ *= invl; pyW *= invl;
+ float nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32;
+ invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ);
+ nzX *= invl; nzY *= invl; nzZ *= invl; nzW *= invl;
+ float pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32;
+ invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ);
+ pzX *= invl; pzY *= invl; pzZ *= invl; pzW *= invl;
+ return nxX * x + nxY * y + nxZ * z + nxW >= -r && pxX * x + pxY * y + pxZ * z + pxW >= -r &&
+ nyX * x + nyY * y + nyZ * z + nyW >= -r && pyX * x + pyY * y + pyZ * z + pyW >= -r &&
+ nzX * x + nzY * y + nzZ * z + nzW >= -r && pzX * x + pzY * y + pzZ * z + pzW >= -r;
+ }
+
+ public boolean testAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ float nxX = m03 + m00, nxY = m13 + m10, nxZ = m23 + m20, nxW = m33 + m30;
+ float pxX = m03 - m00, pxY = m13 - m10, pxZ = m23 - m20, pxW = m33 - m30;
+ float nyX = m03 + m01, nyY = m13 + m11, nyZ = m23 + m21, nyW = m33 + m31;
+ float pyX = m03 - m01, pyY = m13 - m11, pyZ = m23 - m21, pyW = m33 - m31;
+ float nzX = m03 + m02, nzY = m13 + m12, nzZ = m23 + m22, nzW = m33 + m32;
+ float pzX = m03 - m02, pzY = m13 - m12, pzZ = m23 - m22, pzW = m33 - m32;
+ /*
+ * This is an implementation of the "2.4 Basic intersection test" of the mentioned site.
+ * It does not distinguish between partially inside and fully inside, though, so the test with the 'p' vertex is omitted.
+ */
+ return nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW &&
+ pxX * (pxX < 0 ? minX : maxX) + pxY * (pxY < 0 ? minY : maxY) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW &&
+ nyX * (nyX < 0 ? minX : maxX) + nyY * (nyY < 0 ? minY : maxY) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW &&
+ pyX * (pyX < 0 ? minX : maxX) + pyY * (pyY < 0 ? minY : maxY) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW &&
+ nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW &&
+ pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @return this
+ */
+ public Matrix4f obliqueZ(float a, float b) {
+ this.m20 = m00 * a + m10 * b + m20;
+ this.m21 = m01 * a + m11 * b + m21;
+ this.m22 = m02 * a + m12 * b + m22;
+ this._properties(this.properties & PROPERTY_AFFINE);
+ return this;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4f obliqueZ(float a, float b, Matrix4f dest) {
+ dest._m00(m00)
+ ._m01(m01)
+ ._m02(m02)
+ ._m03(m03)
+ ._m10(m10)
+ ._m11(m11)
+ ._m12(m12)
+ ._m13(m13)
+ ._m20(m00 * a + m10 * b + m20)
+ ._m21(m01 * a + m11 * b + m21)
+ ._m22(m02 * a + m12 * b + m22)
+ ._m23(m23)
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._m33(m33)
+ ._properties(this.properties & PROPERTY_AFFINE);
+ return dest;
+ }
+
+ /**
+ * Create a view and projection matrix from a given eye
position, a given bottom left corner position p
of the near plane rectangle
+ * and the extents of the near plane rectangle along its local x
and y
axes, and store the resulting matrices
+ * in projDest
and viewDest
.
+ *
+ * This method creates a view and perspective projection matrix assuming that there is a pinhole camera at position eye
+ * projecting the scene onto the near plane defined by the rectangle.
+ *
+ * All positions and lengths are in the same (world) unit.
+ *
+ * @param eye
+ * the position of the camera
+ * @param p
+ * the bottom left corner of the near plane rectangle (will map to the bottom left corner in window coordinates)
+ * @param x
+ * the direction and length of the local "bottom/top" X axis/side of the near plane rectangle
+ * @param y
+ * the direction and length of the local "left/right" Y axis/side of the near plane rectangle
+ * @param nearFarDist
+ * the distance between the far and near plane (the near plane will be calculated by this method).
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * If the special value {@link Float#NEGATIVE_INFINITY} is used, the near and far planes will be swapped and
+ * the near clipping plane will be at positive infinity.
+ * If a negative value is used (except for {@link Float#NEGATIVE_INFINITY}) the near and far planes will be swapped
+ * @param zeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param projDest
+ * will hold the resulting projection matrix
+ * @param viewDest
+ * will hold the resulting view matrix
+ */
+ public static void projViewFromRectangle(
+ Vector3f eye, Vector3f p, Vector3f x, Vector3f y, float nearFarDist, boolean zeroToOne,
+ Matrix4f projDest, Matrix4f viewDest) {
+ float zx = y.y * x.z - y.z * x.y, zy = y.z * x.x - y.x * x.z, zz = y.x * x.y - y.y * x.x;
+ float zd = zx * (p.x - eye.x) + zy * (p.y - eye.y) + zz * (p.z - eye.z);
+ float zs = zd >= 0 ? 1 : -1; zx *= zs; zy *= zs; zz *= zs; zd *= zs;
+ viewDest.setLookAt(eye.x, eye.y, eye.z, eye.x + zx, eye.y + zy, eye.z + zz, y.x, y.y, y.z);
+ float px = viewDest.m00 * p.x + viewDest.m10 * p.y + viewDest.m20 * p.z + viewDest.m30;
+ float py = viewDest.m01 * p.x + viewDest.m11 * p.y + viewDest.m21 * p.z + viewDest.m31;
+ float tx = viewDest.m00 * x.x + viewDest.m10 * x.y + viewDest.m20 * x.z;
+ float ty = viewDest.m01 * y.x + viewDest.m11 * y.y + viewDest.m21 * y.z;
+ float len = Math.sqrt(zx * zx + zy * zy + zz * zz);
+ float near = zd / len, far;
+ if (Float.isInfinite(nearFarDist) && nearFarDist < 0.0f) {
+ far = near;
+ near = Float.POSITIVE_INFINITY;
+ } else if (Float.isInfinite(nearFarDist) && nearFarDist > 0.0f) {
+ far = Float.POSITIVE_INFINITY;
+ } else if (nearFarDist < 0.0f) {
+ far = near;
+ near = near + nearFarDist;
+ } else {
+ far = near + nearFarDist;
+ }
+ projDest.setFrustum(px, px + tx, py, py + ty, near, far, zeroToOne);
+ }
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector up
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from
+ * {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc)} called with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector up
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4f withLookAtUp(Vector3fc up) {
+ return withLookAtUp(up.x(), up.y(), up.z(), this);
+ }
+
+ public Matrix4f withLookAtUp(Vector3fc up, Matrix4f dest) {
+ return withLookAtUp(up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector (upX, upY, upZ)
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from
+ * {@link #setLookAt(float, float, float, float, float, float, float, float, float)} called with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector (upX, upY, upZ)
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param upX
+ * the x coordinate of the up vector
+ * @param upY
+ * the y coordinate of the up vector
+ * @param upZ
+ * the z coordinate of the up vector
+ * @return this
+ */
+ public Matrix4f withLookAtUp(float upX, float upY, float upZ) {
+ return withLookAtUp(upX, upY, upZ, this);
+ }
+
+ public Matrix4f withLookAtUp(float upX, float upY, float upZ, Matrix4f dest) {
+ float y = (upY * m21 - upZ * m11) * m02 +
+ (upZ * m01 - upX * m21) * m12 +
+ (upX * m11 - upY * m01) * m22;
+ float x = upX * m01 + upY * m11 + upZ * m21;
+ if ((properties & PROPERTY_ORTHONORMAL) == 0)
+ x *= Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21);
+ float invsqrt = Math.invsqrt(y * y + x * x);
+ float c = x * invsqrt, s = y * invsqrt;
+ float nm00 = c * m00 - s * m01, nm10 = c * m10 - s * m11, nm20 = c * m20 - s * m21, nm31 = s * m30 + c * m31;
+ float nm01 = s * m00 + c * m01, nm11 = s * m10 + c * m11, nm21 = s * m20 + c * m21, nm30 = c * m30 - s * m31;
+ dest._m00(nm00)._m10(nm10)._m20(nm20)._m30(nm30)
+ ._m01(nm01)._m11(nm11)._m21(nm21)._m31(nm31);
+ if (dest != this) {
+ dest._m02(m02)._m12(m12)._m22(m22)._m32(m32)
+ ._m03(m03)._m13(m13)._m23(m23)._m33(m33);
+ }
+ dest._properties(properties & ~(PROPERTY_PERSPECTIVE | PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapXZY() {
+ return mapXZY(this);
+ }
+ public Matrix4f mapXZY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapXZnY() {
+ return mapXZnY(this);
+ }
+ public Matrix4f mapXZnY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapXnYnZ() {
+ return mapXnYnZ(this);
+ }
+ public Matrix4f mapXnYnZ(Matrix4f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapXnZY() {
+ return mapXnZY(this);
+ }
+ public Matrix4f mapXnZY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapXnZnY() {
+ return mapXnZnY(this);
+ }
+ public Matrix4f mapXnZnY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYXZ() {
+ return mapYXZ(this);
+ }
+ public Matrix4f mapYXZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYXnZ() {
+ return mapYXnZ(this);
+ }
+ public Matrix4f mapYXnZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYZX() {
+ return mapYZX(this);
+ }
+ public Matrix4f mapYZX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYZnX() {
+ return mapYZnX(this);
+ }
+ public Matrix4f mapYZnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYnXZ() {
+ return mapYnXZ(this);
+ }
+ public Matrix4f mapYnXZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYnXnZ() {
+ return mapYnXnZ(this);
+ }
+ public Matrix4f mapYnXnZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYnZX() {
+ return mapYnZX(this);
+ }
+ public Matrix4f mapYnZX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapYnZnX() {
+ return mapYnZnX(this);
+ }
+ public Matrix4f mapYnZnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZXY() {
+ return mapZXY(this);
+ }
+ public Matrix4f mapZXY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZXnY() {
+ return mapZXnY(this);
+ }
+ public Matrix4f mapZXnY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZYX() {
+ return mapZYX(this);
+ }
+ public Matrix4f mapZYX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZYnX() {
+ return mapZYnX(this);
+ }
+ public Matrix4f mapZYnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZnXY() {
+ return mapZnXY(this);
+ }
+ public Matrix4f mapZnXY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZnXnY() {
+ return mapZnXnY(this);
+ }
+ public Matrix4f mapZnXnY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZnYX() {
+ return mapZnYX(this);
+ }
+ public Matrix4f mapZnYX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapZnYnX() {
+ return mapZnYnX(this);
+ }
+ public Matrix4f mapZnYnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXYnZ() {
+ return mapnXYnZ(this);
+ }
+ public Matrix4f mapnXYnZ(Matrix4f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXZY() {
+ return mapnXZY(this);
+ }
+ public Matrix4f mapnXZY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXZnY() {
+ return mapnXZnY(this);
+ }
+ public Matrix4f mapnXZnY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXnYZ() {
+ return mapnXnYZ(this);
+ }
+ public Matrix4f mapnXnYZ(Matrix4f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXnYnZ() {
+ return mapnXnYnZ(this);
+ }
+ public Matrix4f mapnXnYnZ(Matrix4f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXnZY() {
+ return mapnXnZY(this);
+ }
+ public Matrix4f mapnXnZY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnXnZnY() {
+ return mapnXnZnY(this);
+ }
+ public Matrix4f mapnXnZnY(Matrix4f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYXZ() {
+ return mapnYXZ(this);
+ }
+ public Matrix4f mapnYXZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYXnZ() {
+ return mapnYXnZ(this);
+ }
+ public Matrix4f mapnYXnZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYZX() {
+ return mapnYZX(this);
+ }
+ public Matrix4f mapnYZX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYZnX() {
+ return mapnYZnX(this);
+ }
+ public Matrix4f mapnYZnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(m20)._m11(m21)._m12(m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYnXZ() {
+ return mapnYnXZ(this);
+ }
+ public Matrix4f mapnYnXZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYnXnZ() {
+ return mapnYnXnZ(this);
+ }
+ public Matrix4f mapnYnXnZ(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYnZX() {
+ return mapnYnZX(this);
+ }
+ public Matrix4f mapnYnZX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnYnZnX() {
+ return mapnYnZnX(this);
+ }
+ public Matrix4f mapnYnZnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m03(m03)._m10(-m20)._m11(-m21)._m12(-m22)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZXY() {
+ return mapnZXY(this);
+ }
+ public Matrix4f mapnZXY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZXnY() {
+ return mapnZXnY(this);
+ }
+ public Matrix4f mapnZXnY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m00)._m11(m01)._m12(m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZYX() {
+ return mapnZYX(this);
+ }
+ public Matrix4f mapnZYX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZYnX() {
+ return mapnZYnX(this);
+ }
+ public Matrix4f mapnZYnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZnXY() {
+ return mapnZnXY(this);
+ }
+ public Matrix4f mapnZnXY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(m10)._m21(m11)._m22(m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZnXnY() {
+ return mapnZnXnY(this);
+ }
+ public Matrix4f mapnZnXnY(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m00)._m11(-m01)._m12(-m02)._m13(m13)._m20(-m10)._m21(-m11)._m22(-m12)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZnYX() {
+ return mapnZnYX(this);
+ }
+ public Matrix4f mapnZnYX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m00)._m21(m01)._m22(m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f mapnZnYnX() {
+ return mapnZnYnX(this);
+ }
+ public Matrix4f mapnZnYnX(Matrix4f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(-m00)._m21(-m01)._m22(-m02)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33)._properties(properties & (PROPERTY_AFFINE | PROPERTY_ORTHONORMAL));
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f negateX() {
+ return _m00(-m00)._m01(-m01)._m02(-m02);
+ }
+ public Matrix4f negateX(Matrix4f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f negateY() {
+ return _m10(-m10)._m11(-m11)._m12(-m12);
+ }
+ public Matrix4f negateY(Matrix4f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(-m10)._m11(-m11)._m12(-m12)._m13(m13)._m20(m20)._m21(m21)._m22(m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ *
+ * @return this
+ */
+ public Matrix4f negateZ() {
+ return _m20(-m20)._m21(-m21)._m22(-m22);
+ }
+ public Matrix4f negateZ(Matrix4f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m03(m03)._m10(m10)._m11(m11)._m12(m12)._m13(m13)._m20(-m20)._m21(-m21)._m22(-m22)._m23(m23)._m30(m30)._m31(m31)._m32(m32)._m33(m33);
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) && Math.isFinite(m03) &&
+ Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) && Math.isFinite(m13) &&
+ Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) && Math.isFinite(m23) &&
+ Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32) && Math.isFinite(m33);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4fStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4fStack.java
new file mode 100644
index 000000000..c768bd4b4
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4fStack.java
@@ -0,0 +1,185 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix4f} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix4fStack} class inherits from {@link Matrix4f}, so the current/top matrix is always the {@link Matrix4fStack}/{@link Matrix4f} itself. This
+ * affects all operations in {@link Matrix4f} that take another {@link Matrix4f} as parameter. If a {@link Matrix4fStack} is used as argument to those methods,
+ * the effective argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix4fStack extends Matrix4f {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix4fStack(int) constructor}.
+ */
+ private Matrix4f[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix4fStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix4fStack} simply only consists of this
+ * {@link Matrix4f}
+ */
+ public Matrix4fStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix4f[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix4f();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix4fStack} instance.
+ */
+ public Matrix4fStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix4fStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix4fStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix4fStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix4f and Matrix4fStack:
+ *
+ * - Matrix4f.equals(Matrix4fStack) is true iff all the 16 matrix elements are equal
+ * - Matrix4fStack.equals(Matrix4f) is true iff all the 16 matrix elements are equal
+ * - Matrix4fStack.equals(Matrix4fStack) is true iff all 16 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix4fStack) {
+ Matrix4fStack other = (Matrix4fStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix4fStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix4f m = new Matrix4f();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix4fStack cloned = (Matrix4fStack) super.clone();
+ Matrix4f[] clonedMats = new Matrix4f[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix4f) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4fc.java
new file mode 100644
index 000000000..8b32de51f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4fc.java
@@ -0,0 +1,6082 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+
+/**
+ * Interface to a read-only view of a 4x4 matrix of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix4fc {
+
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation x=-1
when using the identity matrix.
+ */
+ int PLANE_NX = 0;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation x=1
when using the identity matrix.
+ */
+ int PLANE_PX = 1;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation y=-1
when using the identity matrix.
+ */
+ int PLANE_NY = 2;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation y=1
when using the identity matrix.
+ */
+ int PLANE_PY = 3;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation z=-1
when using the identity matrix.
+ */
+ int PLANE_NZ = 4;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation z=1
when using the identity matrix.
+ */
+ int PLANE_PZ = 5;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (-1, -1, -1)
when using the identity matrix.
+ */
+ int CORNER_NXNYNZ = 0;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (1, -1, -1)
when using the identity matrix.
+ */
+ int CORNER_PXNYNZ = 1;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (1, 1, -1)
when using the identity matrix.
+ */
+ int CORNER_PXPYNZ = 2;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (-1, 1, -1)
when using the identity matrix.
+ */
+ int CORNER_NXPYNZ = 3;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (1, -1, 1)
when using the identity matrix.
+ */
+ int CORNER_PXNYPZ = 4;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (-1, -1, 1)
when using the identity matrix.
+ */
+ int CORNER_NXNYPZ = 5;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (-1, 1, 1)
when using the identity matrix.
+ */
+ int CORNER_NXPYPZ = 6;
+ /**
+ * Argument to the first parameter of {@link #frustumCorner(int, Vector3f)}
+ * identifying the corner (1, 1, 1)
when using the identity matrix.
+ */
+ int CORNER_PXPYPZ = 7;
+
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents a perspective transformation.
+ */
+ byte PROPERTY_PERSPECTIVE = 1<<0;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents an affine transformation.
+ */
+ byte PROPERTY_AFFINE = 1<<1;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation.
+ */
+ byte PROPERTY_IDENTITY = 1<<2;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation.
+ */
+ byte PROPERTY_TRANSLATION = 1<<3;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the upper-left 3x3 submatrix represents an orthogonal
+ * matrix (i.e. orthonormal basis). For practical reasons, this property also always implies
+ * {@link #PROPERTY_AFFINE} in this implementation.
+ */
+ byte PROPERTY_ORTHONORMAL = 1<<4;
+
+ /**
+ * Return the assumed properties of this matrix. This is a bit-combination of
+ * {@link #PROPERTY_IDENTITY}, {@link #PROPERTY_AFFINE},
+ * {@link #PROPERTY_TRANSLATION} and {@link #PROPERTY_PERSPECTIVE}.
+ *
+ * @return the properties of the matrix
+ */
+ int properties();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m01();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m02();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ float m03();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m11();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m12();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ float m13();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m21();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m22();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ float m23();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m30();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m31();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m32();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 3.
+ *
+ * @return the value of the matrix element
+ */
+ float m33();
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mul(Matrix4fc right, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * This method neither assumes nor checks for any matrix properties of this
or right
+ * and will always perform a complete 4x4 matrix multiplication. This method should only be used whenever the
+ * multiplied matrices do not have any properties for which there are optimized multiplication methods available.
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mul0(Matrix4fc right, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the matrix with the supplied elements and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r03
+ * the m03 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r13
+ * the m13 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @param r23
+ * the m23 element of the right matrix
+ * @param r30
+ * the m30 element of the right matrix
+ * @param r31
+ * the m31 element of the right matrix
+ * @param r32
+ * the m32 element of the right matrix
+ * @param r33
+ * the m33 element of the right matrix
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mul(
+ float r00, float r01, float r02, float r03,
+ float r10, float r11, float r12, float r13,
+ float r20, float r21, float r22, float r23,
+ float r30, float r31, float r32, float r33, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the 3x3 matrix with the supplied elements expanded to a 4x4 matrix with
+ * all other matrix elements set to identity, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix whose
+ * elements are supplied via the parameters, then the new matrix will be M * R
.
+ * So when transforming a vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param r00
+ * the m00 element of the right matrix
+ * @param r01
+ * the m01 element of the right matrix
+ * @param r02
+ * the m02 element of the right matrix
+ * @param r10
+ * the m10 element of the right matrix
+ * @param r11
+ * the m11 element of the right matrix
+ * @param r12
+ * the m12 element of the right matrix
+ * @param r20
+ * the m20 element of the right matrix
+ * @param r21
+ * the m21 element of the right matrix
+ * @param r22
+ * the m22 element of the right matrix
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return this
+ */
+ Matrix4f mul3x3(
+ float r00, float r01, float r02,
+ float r10, float r11, float r12,
+ float r20, float r21, float r22, Matrix4f dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulLocal(Matrix4fc left, Matrix4f dest);
+
+ /**
+ * Pre-multiply this matrix by the supplied left
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that this
matrix and the given left
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of left
.
+ *
+ * If M
is this
matrix and L
the left
matrix,
+ * then the new matrix will be L * M
. So when transforming a
+ * vector v
with the new matrix by using L * M * v
, the
+ * transformation of this
matrix will be applied first!
+ *
+ * @param left
+ * the left operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulLocalAffine(Matrix4fc left, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mul(Matrix3x2fc right, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * The last row of the right
matrix is assumed to be (0, 0, 0, 1)
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mul(Matrix4x3fc right, Matrix4f dest);
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied {@link #isAffine() affine} view
matrix and store the result in dest
.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the {@link #isAffine() affine} matrix to multiply this
symmetric perspective projection matrix by
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulPerspectiveAffine(Matrix4fc view, Matrix4f dest);
+
+ /**
+ * Multiply this
symmetric perspective projection matrix by the supplied view
matrix and store the result in dest
.
+ *
+ * If P
is this
matrix and V
the view
matrix,
+ * then the new matrix will be P * V
. So when transforming a
+ * vector v
with the new matrix by using P * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix to multiply this
symmetric perspective projection matrix by
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulPerspectiveAffine(Matrix4x3fc view, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, which is assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that the given right
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulAffineR(Matrix4fc right, Matrix4f dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix, both of which are assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that this
matrix and the given right
matrix both represent an {@link #isAffine() affine} transformation
+ * (i.e. their last rows are equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrices only represent affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulAffine(Matrix4fc right, Matrix4f dest);
+
+ /**
+ * Multiply this matrix, which is assumed to only contain a translation, by the supplied right
matrix, which is assumed to be {@link #isAffine() affine}, and store the result in dest
.
+ *
+ * This method assumes that this
matrix only contains a translation, and that the given right
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
).
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication (the last row is assumed to be (0, 0, 0, 1)
)
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulTranslationAffine(Matrix4fc right, Matrix4f dest);
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied {@link #isAffine() affine} view
matrix
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the affine matrix which to multiply this
with
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f mulOrthoAffine(Matrix4fc view, Matrix4f dest);
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * by first multiplying each component of other
's 4x3 submatrix by otherFactor
,
+ * adding that to this
and storing the final result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * The matrices this
and other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's 4x3 components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f fma4x3(Matrix4fc other, float otherFactor, Matrix4f dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f add(Matrix4fc other, Matrix4f dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f sub(Matrix4fc subtrahend, Matrix4f dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mulComponentWise(Matrix4fc other, Matrix4f dest);
+
+ /**
+ * Component-wise add the upper 4x3 submatrices of this
and other
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f add4x3(Matrix4fc other, Matrix4f dest);
+
+ /**
+ * Component-wise subtract the upper 4x3 submatrices of subtrahend
from this
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f sub4x3(Matrix4fc subtrahend, Matrix4f dest);
+
+ /**
+ * Component-wise multiply the upper 4x3 submatrices of this
by other
+ * and store the result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mul4x3ComponentWise(Matrix4fc other, Matrix4f dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * If this
matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing,
+ * and thus its last row is equal to (0, 0, 0, 1)
, then {@link #determinantAffine()} can be used instead of this method.
+ *
+ * @see #determinantAffine()
+ *
+ * @return the determinant
+ */
+ float determinant();
+
+ /**
+ * Return the determinant of the upper left 3x3 submatrix of this matrix.
+ *
+ * @return the determinant
+ */
+ float determinant3x3();
+
+ /**
+ * Return the determinant of this matrix by assuming that it represents an {@link #isAffine() affine} transformation and thus
+ * its last row is equal to (0, 0, 0, 1)
.
+ *
+ * @return the determinant
+ */
+ float determinantAffine();
+
+ /**
+ * Invert this matrix and write the result into dest
.
+ *
+ * If this
matrix represents an {@link #isAffine() affine} transformation, such as translation, rotation, scaling and shearing,
+ * and thus its last row is equal to (0, 0, 0, 1)
, then {@link #invertAffine(Matrix4f)} can be used instead of this method.
+ *
+ * @see #invertAffine(Matrix4f)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f invert(Matrix4f dest);
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float, Matrix4f) perspective()} methods,
+ * that is, if this
is a symmetrical perspective frustum transformation,
+ * then this method builds the inverse of this
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix when being obtained via {@link #perspective(float, float, float, float, Matrix4f) perspective()}.
+ *
+ * @see #perspective(float, float, float, float, Matrix4f)
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4f invertPerspective(Matrix4f dest);
+
+ /**
+ * If this
is an arbitrary perspective projection matrix obtained via one of the {@link #frustum(float, float, float, float, float, float, Matrix4f) frustum()} methods,
+ * then this method builds the inverse of this
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of a perspective projection matrix.
+ *
+ * If this matrix represents a symmetric perspective frustum transformation, as obtained via {@link #perspective(float, float, float, float, Matrix4f) perspective()}, then
+ * {@link #invertPerspective(Matrix4f)} should be used instead.
+ *
+ * @see #frustum(float, float, float, float, float, float, Matrix4f)
+ * @see #invertPerspective(Matrix4f)
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4f invertFrustum(Matrix4f dest);
+
+ /**
+ * Invert this
orthographic projection matrix and store the result into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4f invertOrtho(Matrix4f dest);
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float, Matrix4f) perspective()} methods,
+ * that is, if this
is a symmetrical perspective frustum transformation
+ * and the given view
matrix is {@link #isAffine() affine} and has unit scaling (for example by being obtained via {@link #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f) lookAt()}),
+ * then this method builds the inverse of this * view
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of the combination of the view and projection matrices, when both were obtained
+ * via the common methods {@link #perspective(float, float, float, float, Matrix4f) perspective()} and {@link #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f) lookAt()} or
+ * other methods, that build affine matrices, such as {@link #translate(float, float, float, Matrix4f) translate} and {@link #rotate(float, float, float, float, Matrix4f)}, except for {@link #scale(float, float, float, Matrix4f) scale()}.
+ *
+ * For the special cases of the matrices this
and view
mentioned above, this method is equivalent to the following code:
+ *
+ * dest.set(this).mul(view).invert();
+ *
+ *
+ * @param view
+ * the view transformation (must be {@link #isAffine() affine} and have unit scaling)
+ * @param dest
+ * will hold the inverse of this * view
+ * @return dest
+ */
+ Matrix4f invertPerspectiveView(Matrix4fc view, Matrix4f dest);
+
+ /**
+ * If this
is a perspective projection matrix obtained via one of the {@link #perspective(float, float, float, float, Matrix4f) perspective()} methods,
+ * that is, if this
is a symmetrical perspective frustum transformation
+ * and the given view
matrix has unit scaling,
+ * then this method builds the inverse of this * view
and stores it into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of the combination of the view and projection matrices, when both were obtained
+ * via the common methods {@link #perspective(float, float, float, float, Matrix4f) perspective()} and {@link #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f) lookAt()} or
+ * other methods, that build affine matrices, such as {@link #translate(float, float, float, Matrix4f) translate} and {@link #rotate(float, float, float, float, Matrix4f)}, except for {@link #scale(float, float, float, Matrix4f) scale()}.
+ *
+ * For the special cases of the matrices this
and view
mentioned above, this method is equivalent to the following code:
+ *
+ * dest.set(this).mul(view).invert();
+ *
+ *
+ * @param view
+ * the view transformation (must have unit scaling)
+ * @param dest
+ * will hold the inverse of this * view
+ * @return dest
+ */
+ Matrix4f invertPerspectiveView(Matrix4x3fc view, Matrix4f dest);
+
+ /**
+ * Invert this matrix by assuming that it is an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and write the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f invertAffine(Matrix4f dest);
+
+ /**
+ * Transpose this matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f transpose(Matrix4f dest);
+
+ /**
+ * Transpose only the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * All other matrix elements are left unchanged.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f transpose3x3(Matrix4f dest);
+
+ /**
+ * Transpose only the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f transpose3x3(Matrix3f dest);
+
+ /**
+ * Get only the translation components (m30, m31, m32)
of this matrix and store them in the given vector xyz
.
+ *
+ * @param dest
+ * will hold the translation components of this matrix
+ * @return dest
+ */
+ Vector3f getTranslation(Vector3f dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
, y
and z
+ * @return dest
+ */
+ Vector3f getScale(Vector3f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4f get(Matrix4f dest);
+
+ /**
+ * Get the current values of the upper 4x3 submatrix of this
matrix and store them into
+ * dest
.
+ *
+ * @see Matrix4x3f#set(Matrix4fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4x3f get4x3(Matrix4x3f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4d get(Matrix4d dest);
+
+ /**
+ * Get the current values of the upper left 3x3 submatrix of this
matrix and store them into
+ * dest
.
+ *
+ * @see Matrix3f#set(Matrix4fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3f get3x3(Matrix3f dest);
+
+ /**
+ * Get the current values of the upper left 3x3 submatrix of this
matrix and store them into
+ * dest
.
+ *
+ * @see Matrix3d#set(Matrix4fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix3d get3x3(Matrix3d dest);
+
+ /**
+ * Get the rotational component of this
matrix and store the represented rotation
+ * into the given {@link AxisAngle4f}.
+ *
+ * @see AxisAngle4f#set(Matrix4fc)
+ *
+ * @param dest
+ * the destination {@link AxisAngle4f}
+ * @return the passed in destination
+ */
+ AxisAngle4f getRotation(AxisAngle4f dest);
+
+ /**
+ * Get the rotational component of this
matrix and store the represented rotation
+ * into the given {@link AxisAngle4d}.
+ *
+ * @see AxisAngle4f#set(Matrix4fc)
+ *
+ * @param dest
+ * the destination {@link AxisAngle4d}
+ * @return the passed in destination
+ */
+ AxisAngle4d getRotation(AxisAngle4d dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaternionf#setFromUnnormalized(Matrix4fc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getUnnormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are normalized.
+ *
+ * @see Quaternionf#setFromNormalized(Matrix4fc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getNormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaterniond#setFromUnnormalized(Matrix4fc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getUnnormalizedRotation(Quaterniond dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the upper left 3x3 submatrix are normalized.
+ *
+ * @see Quaterniond#setFromNormalized(Matrix4fc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getNormalizedRotation(Quaterniond dest);
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x3(FloatBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x3(int index, FloatBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x3(ByteBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x3(int index, ByteBuffer buffer);
+
+ /**
+ * Store the left 3x4 submatrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get3x4(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x4(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of the left 3x4 submatrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x4(FloatBuffer buffer);
+
+ /**
+ * Store the left 3x4 submatrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of the left 3x4 submatrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x4(int index, FloatBuffer buffer);
+
+ /**
+ * Store the left 3x4 submatrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of the left 3x4 submatrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x4(ByteBuffer buffer);
+
+ /**
+ * Store the left 3x4 submatrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of the left 3x4 submatrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(FloatBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(int index, FloatBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store the transpose of this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get4x3Transposed(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x3Transposed(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x3Transposed(FloatBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x3Transposed(int index, FloatBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x3Transposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x3Transposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x3Transposed(ByteBuffer buffer);
+
+ /**
+ * Store the upper 4x3 submatrix of this
matrix in row-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of the upper 4x3 submatrix in row-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x3Transposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix4fc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in that vector.
+ *
+ * @see Vector4f#mul(Matrix4fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4f transform(Vector4f v);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in dest
.
+ *
+ * @see Vector4f#mul(Matrix4fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transform(Vector4fc v, Vector4f dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transform(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Transform/multiply the given vector by the transpose of this matrix and store the result in that vector.
+ *
+ * @see Vector4f#mulTranspose(Matrix4fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4f transformTranspose(Vector4f v);
+
+ /**
+ * Transform/multiply the given vector by the transpose of this matrix and store the result in dest
.
+ *
+ * @see Vector4f#mulTranspose(Matrix4fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transformTranspose(Vector4fc v, Vector4f dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by the transpose of this matrix and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transformTranspose(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in that vector.
+ *
+ * @see Vector4f#mulProject(Matrix4fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4f transformProject(Vector4f v);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * @see Vector4f#mulProject(Matrix4fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transformProject(Vector4fc v, Vector4f dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transformProject(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in that vector.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @see Vector3f#mulProject(Matrix4fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transformProject(Vector3f v);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @see Vector3f#mulProject(Matrix4fc, Vector3f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3f transformProject(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform/multiply the given vector by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * @see Vector4f#mulProject(Matrix4fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the (x, y, z)
components of the result
+ * @return dest
+ */
+ Vector3f transformProject(Vector4fc v, Vector3f dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z)
by this matrix, perform perspective divide and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector3f transformProject(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform/multiply the vector (x, y, z, w)
by this matrix, perform perspective divide and store
+ * (x, y, z)
of the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param w
+ * the w coordinate of the vector to transform
+ * @param dest
+ * will contain the (x, y, z)
components of the result
+ * @return dest
+ */
+ Vector3f transformProject(float x, float y, float z, float w, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction. This method is therefore
+ * not suited for perspective projection transformations as it will not save the
+ * w
component of the transformed vector.
+ * For perspective projection use {@link #transform(Vector4f)} or {@link #transformProject(Vector3f)}
+ * when perspective divide should be applied, too.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector3fc, Vector3f)}.
+ *
+ * @see #transformPosition(Vector3fc, Vector3f)
+ * @see #transform(Vector4f)
+ * @see #transformProject(Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transformPosition(Vector3f v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction. This method is therefore
+ * not suited for perspective projection transformations as it will not save the
+ * w
component of the transformed vector.
+ * For perspective projection use {@link #transform(Vector4fc, Vector4f)} or
+ * {@link #transformProject(Vector3fc, Vector3f)} when perspective divide should be applied, too.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector3f)}.
+ *
+ * @see #transformPosition(Vector3f)
+ * @see #transform(Vector4fc, Vector4f)
+ * @see #transformProject(Vector3fc, Vector3f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPosition(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform/multiply the 3D-vector (x, y, z)
, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction. This method is therefore
+ * not suited for perspective projection transformations as it will not save the
+ * w
component of the transformed vector.
+ * For perspective projection use {@link #transform(float, float, float, float, Vector4f)} or
+ * {@link #transformProject(float, float, float, Vector3f)} when perspective divide should be applied, too.
+ *
+ * @see #transform(float, float, float, float, Vector4f)
+ * @see #transformProject(float, float, float, Vector3f)
+ *
+ * @param x
+ * the x coordinate of the position
+ * @param y
+ * the y coordinate of the position
+ * @param z
+ * the z coordinate of the position
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPosition(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector3fc, Vector3f)}.
+ *
+ * @see #transformDirection(Vector3fc, Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transformDirection(Vector3f v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector3f)}.
+ *
+ * @see #transformDirection(Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformDirection(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 3D-vector (x, y, z)
, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * @param x
+ * the x coordinate of the direction to transform
+ * @param y
+ * the y coordinate of the direction to transform
+ * @param z
+ * the z coordinate of the direction to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformDirection(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 4D-vector by assuming that this
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
).
+ *
+ * In order to store the result in another vector, use {@link #transformAffine(Vector4fc, Vector4f)}.
+ *
+ * @see #transformAffine(Vector4fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4f transformAffine(Vector4f v);
+
+ /**
+ * Transform/multiply the given 4D-vector by assuming that this
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
) and store the result in dest
.
+ *
+ * In order to store the result in the same vector, use {@link #transformAffine(Vector4f)}.
+ *
+ * @see #transformAffine(Vector4f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformAffine(Vector4fc v, Vector4f dest);
+
+ /**
+ * Transform/multiply the 4D-vector (x, y, z, w)
by assuming that this
matrix represents an {@link #isAffine() affine} transformation
+ * (i.e. its last row is equal to (0, 0, 0, 1)
) and store the result in dest
.
+ *
+ * @param x
+ * the x coordinate of the direction to transform
+ * @param y
+ * the y coordinate of the direction to transform
+ * @param z
+ * the z coordinate of the direction to transform
+ * @param w
+ * the w coordinate of the direction to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformAffine(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scale(Vector3fc xyz, Matrix4f dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * Individual scaling of all three axes can be applied using {@link #scale(float, float, float, Matrix4f)}.
+ *
+ * @see #scale(float, float, float, Matrix4f)
+ *
+ * @param xyz
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scale(float xyz, Matrix4f dest);
+
+ /**
+ * Apply scaling to this matrix by by scaling the X axis by x
and the Y axis by y
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scaleXY(float x, float y, Matrix4f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scale(float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scaleAround(float sx, float sy, float sz, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4f scaleAround(float factor, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling all base axes by the given xyz
factor,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param xyz
+ * the factor to scale all three base axes by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scaleLocal(float xyz, Matrix4f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scaleLocal(float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using the given (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4f().translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz).mul(this, dest)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f scaleAroundLocal(float sx, float sy, float sz, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * This method is equivalent to calling: new Matrix4f().translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz).mul(this, dest)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4f scaleAroundLocal(float factor, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateX(float ang, Matrix4f dest);
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateY(float ang, Matrix4f dest);
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateZ(float ang, Matrix4f dest);
+
+ /**
+ * Apply rotation about the Z axis to align the local +X
towards (dirX, dirY)
and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * The vector (dirX, dirY)
must be a unit vector.
+ *
+ * @param dirX
+ * the x component of the normalized direction
+ * @param dirY
+ * the y component of the normalized direction
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4f rotateTowardsXY(float dirX, float dirY, Matrix4f dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateXYZ(float angleX, float angleY, float angleZ, Matrix4f dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAffineXYZ(float angleX, float angleY, float angleZ, Matrix4f dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateZYX(float angleZ, float angleY, float angleX, Matrix4f dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAffineZYX(float angleZ, float angleY, float angleX, Matrix4f dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateYXZ(float angleY, float angleX, float angleZ, Matrix4f dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method assumes that this
matrix represents an {@link #isAffine() affine} transformation (i.e. its last row is equal to (0, 0, 0, 1)
)
+ * and can be used to speed up matrix multiplication if the matrix only represents affine transformations, such as translation, rotation, scaling and shearing (in any combination).
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAffineYXZ(float angleY, float angleX, float angleZ, Matrix4f dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotate(float ang, float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateTranslation(float ang, float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Apply rotation to this {@link #isAffine() affine} matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAffine(float ang, float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateLocal(float ang, float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateLocalX(float ang, Matrix4f dest);
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateLocalY(float ang, Matrix4f dest);
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateLocalZ(float ang, Matrix4f dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f translate(Vector3fc offset, Matrix4f dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f translate(float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f translateLocal(Vector3fc offset, Matrix4f dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f translateLocal(float x, float y, float z, Matrix4f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, boolean, Matrix4f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4f orthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f orthoSymmetric(float width, float height, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, boolean, Matrix4f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4f orthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f orthoSymmetricLH(float width, float height, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix
+ * and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4f) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float, Matrix4f)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f ortho2D(float left, float right, float bottom, float top, Matrix4f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4f) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float, Matrix4f)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f ortho2DLH(float left, float right, float bottom, float top, Matrix4f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3fc, Vector3fc, Vector3fc, Matrix4f) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAlong(float, float, float, float, float, float, Matrix4f)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc, Matrix4f)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAlong(Vector3fc dir, Vector3fc up, Matrix4f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAt(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc, Matrix4f)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustum(float, float, float, float, float, float, Matrix4f) frustum()} or {@link #perspective(float, float, float, float, Matrix4f) perspective()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAtPerspective(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float, Matrix4f)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc, Matrix4f)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAtLH(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * This method assumes this
to be a perspective transformation, obtained via
+ * {@link #frustumLH(float, float, float, float, float, float, Matrix4f) frustumLH()} or {@link #perspectiveLH(float, float, float, float, Matrix4f) perspectiveLH()} or
+ * one of their overloads.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lookAtPerspectiveLH(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * This method is equivalent to calling: translate(w-1-2*x, h-1-2*y, 0, dest).scale(w, h, 1)
+ *
+ * If M
is this
matrix and T
the created transformation matrix,
+ * then the new matrix will be M * T
. So when transforming a
+ * vector v
with the new matrix by using M * T * v
, the
+ * created transformation will be applied first!
+ *
+ * @param x
+ * the tile's x coordinate/index (should be in [0..w)
)
+ * @param y
+ * the tile's y coordinate/index (should be in [0..h)
)
+ * @param w
+ * the number of tiles along the x axis
+ * @param h
+ * the number of tiles along the y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f tile(int x, int y, int w, int h, Matrix4f dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4f perspective(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f perspective(float fovy, float aspect, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4f perspectiveRect(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f perspectiveRect(float width, float height, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ Matrix4f perspectiveRect(float width, float height, float zNear, float zFar, boolean zZeroToOne);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param width
+ * the width of the near frustum plane
+ * @param height
+ * the height of the near frustum plane
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ Matrix4f perspectiveRect(float width, float height, float zNear, float zFar);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation using for a right-handed coordinate system
+ * the given NDC z range to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar, boolean zZeroToOne);
+
+ /**
+ * Apply an asymmetric off-center perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * The given angles offAngleX
and offAngleY
are the horizontal and vertical angles between
+ * the line of sight and the line given by the center of the near and far frustum planes. So, when offAngleY
+ * is just fovy/2
then the projection frustum is rotated towards +Y and the bottom frustum plane
+ * is parallel to the XZ-plane.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param offAngleX
+ * the horizontal angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param offAngleY
+ * the vertical angle between the line of sight and the line crossing the center of the near and far frustum planes
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @return this
+ */
+ Matrix4f perspectiveOffCenter(float fovy, float offAngleX, float offAngleY, float aspect, float zNear, float zFar);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f perspectiveLH(float fovy, float aspect, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply a symmetric perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and P
the perspective projection matrix,
+ * then the new matrix will be M * P
. So when transforming a
+ * vector v
with the new matrix by using M * P * v
,
+ * the perspective projection will be applied first!
+ *
+ * @param fovy
+ * the vertical field of view in radians (must be greater than zero and less than {@link Math#PI PI})
+ * @param aspect
+ * the aspect ratio (i.e. width / height; must be greater than zero)
+ * @param zNear
+ * near clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f perspectiveLH(float fovy, float aspect, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f frustum(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f frustum(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f frustumLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4f dest);
+
+ /**
+ * Apply an arbitrary perspective projection frustum transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and F
the frustum matrix,
+ * then the new matrix will be M * F
. So when transforming a
+ * vector v
with the new matrix by using M * F * v
,
+ * the frustum transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance along the x-axis to the left frustum edge
+ * @param right
+ * the distance along the x-axis to the right frustum edge
+ * @param bottom
+ * the distance along the y-axis to the bottom frustum edge
+ * @param top
+ * the distance along the y-axis to the top frustum edge
+ * @param zNear
+ * near clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the near clipping plane will be at positive infinity.
+ * In that case, zFar
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param zFar
+ * far clipping plane distance. This value must be greater than zero.
+ * If the special value {@link Float#POSITIVE_INFINITY} is used, the far clipping plane will be at positive infinity.
+ * In that case, zNear
may not also be {@link Float#POSITIVE_INFINITY}.
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f frustumLH(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotate(Quaternionfc quat, Matrix4f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this {@link #isAffine() affine} matrix and store
+ * the result in dest
.
+ *
+ * This method assumes this
to be {@link #isAffine() affine}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAffine(Quaternionfc quat, Matrix4f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - ransformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateTranslation(Quaternionfc quat, Matrix4f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this {@link #isAffine() affine}
+ * matrix while using (ox, oy, oz)
as the rotation origin, and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is only applicable if this
is an {@link #isAffine() affine} matrix.
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAroundAffine(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix while using (ox, oy, oz)
as the rotation origin,
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAround(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateLocal(Quaternionfc quat, Matrix4f dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix while using (ox, oy, oz)
+ * as the rotation origin, and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * This method is equivalent to calling: translateLocal(-ox, -oy, -oz, dest).rotateLocal(quat).translateLocal(ox, oy, oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateAroundLocal(Quaternionfc quat, float ox, float oy, float oz, Matrix4f dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float, Matrix4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotate(AxisAngle4f axisAngle, Matrix4f dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis-angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float, Matrix4f)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3fc#normalize(Vector3f) normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotate(float angle, Vector3fc axis, Matrix4f dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4f)} and then the method {@link #unprojectInv(float, float, float, int[], Vector4f) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(float, float, float, int[], Vector4f)
+ * @see #invert(Matrix4f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4f unproject(float winX, float winY, float winZ, int[] viewport, Vector4f dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4f)} and then the method {@link #unprojectInv(float, float, float, int[], Vector3f) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(float, float, float, int[], Vector3f)
+ * @see #invert(Matrix4f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3f unproject(float winX, float winY, float winZ, int[] viewport, Vector3f dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4f)} and then the method {@link #unprojectInv(float, float, float, int[], Vector4f) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(float, float, float, int[], Vector4f)
+ * @see #unproject(float, float, float, int[], Vector4f)
+ * @see #invert(Matrix4f)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4f unproject(Vector3fc winCoords, int[] viewport, Vector4f dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4f)} and then the method {@link #unprojectInv(float, float, float, int[], Vector3f) unprojectInv()} can be invoked on it.
+ *
+ * @see #unprojectInv(float, float, float, int[], Vector3f)
+ * @see #unproject(float, float, float, int[], Vector3f)
+ * @see #invert(Matrix4f)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3f unproject(Vector3fc winCoords, int[] viewport, Vector3f dest);
+
+ /**
+ * Unproject the given 2D window coordinates (winX, winY)
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4f)} and then the method {@link #unprojectInvRay(float, float, int[], Vector3f, Vector3f) unprojectInvRay()} can be invoked on it.
+ *
+ * @see #unprojectInvRay(float, float, int[], Vector3f, Vector3f)
+ * @see #invert(Matrix4f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4f unprojectRay(float winX, float winY, int[] viewport, Vector3f originDest, Vector3f dirDest);
+
+ /**
+ * Unproject the given 2D window coordinates winCoords
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method first converts the given window coordinates to normalized device coordinates in the range [-1..1]
+ * and then transforms those NDC coordinates by the inverse of this
matrix.
+ *
+ * As a necessary computation step for unprojecting, this method computes the inverse of this
matrix.
+ * In order to avoid computing the matrix inverse with every invocation, the inverse of this
matrix can be built
+ * once outside using {@link #invert(Matrix4f)} and then the method {@link #unprojectInvRay(float, float, int[], Vector3f, Vector3f) unprojectInvRay()} can be invoked on it.
+ *
+ * @see #unprojectInvRay(float, float, int[], Vector3f, Vector3f)
+ * @see #unprojectRay(float, float, int[], Vector3f, Vector3f)
+ * @see #invert(Matrix4f)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4f unprojectRay(Vector2fc winCoords, int[] viewport, Vector3f originDest, Vector3f dirDest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(Vector3fc, int[], Vector4f) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * This method reads the four viewport parameters from the given int[].
+ *
+ * @see #unproject(Vector3fc, int[], Vector4f)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4f unprojectInv(Vector3fc winCoords, int[] viewport, Vector4f dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(float, float, float, int[], Vector4f) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(float, float, float, int[], Vector4f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector4f unprojectInv(float winX, float winY, float winZ, int[] viewport, Vector4f dest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method differs from {@link #unprojectRay(Vector2fc, int[], Vector3f, Vector3f) unprojectRay()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unprojectRay(Vector2fc, int[], Vector3f, Vector3f)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4f unprojectInvRay(Vector2fc winCoords, int[] viewport, Vector3f originDest, Vector3f dirDest);
+
+ /**
+ * Unproject the given 2D window coordinates (winX, winY)
by this
matrix using the specified viewport
+ * and compute the origin and the direction of the resulting ray which starts at NDC z = -1.0
and goes through NDC z = +1.0
.
+ *
+ * This method differs from {@link #unprojectRay(float, float, int[], Vector3f, Vector3f) unprojectRay()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * @see #unprojectRay(float, float, int[], Vector3f, Vector3f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param originDest
+ * will hold the ray origin
+ * @param dirDest
+ * will hold the (unnormalized) ray direction
+ * @return this
+ */
+ Matrix4f unprojectInvRay(float winX, float winY, int[] viewport, Vector3f originDest, Vector3f dirDest);
+
+ /**
+ * Unproject the given window coordinates winCoords
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(Vector3fc, int[], Vector3f) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * The depth range of winCoords.z
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(Vector3fc, int[], Vector3f)
+ *
+ * @param winCoords
+ * the window coordinates to unproject
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3f unprojectInv(Vector3fc winCoords, int[] viewport, Vector3f dest);
+
+ /**
+ * Unproject the given window coordinates (winX, winY, winZ)
by this
matrix using the specified viewport.
+ *
+ * This method differs from {@link #unproject(float, float, float, int[], Vector3f) unproject()}
+ * in that it assumes that this
is already the inverse matrix of the original projection matrix.
+ * It exists to avoid recomputing the matrix inverse with every invocation.
+ *
+ * The depth range of winZ
is assumed to be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #unproject(float, float, float, int[], Vector3f)
+ *
+ * @param winX
+ * the x-coordinate in window coordinates (pixels)
+ * @param winY
+ * the y-coordinate in window coordinates (pixels)
+ * @param winZ
+ * the z-coordinate, which is the depth value in [0..1]
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * will hold the unprojected position
+ * @return dest
+ */
+ Vector3f unprojectInv(float winX, float winY, float winZ, int[] viewport, Vector3f dest);
+
+ /**
+ * Project the given (x, y, z)
position via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @param x
+ * the x-coordinate of the position to project
+ * @param y
+ * the y-coordinate of the position to project
+ * @param z
+ * the z-coordinate of the position to project
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector4f project(float x, float y, float z, int[] viewport, Vector4f winCoordsDest);
+
+ /**
+ * Project the given (x, y, z)
position via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @param x
+ * the x-coordinate of the position to project
+ * @param y
+ * the y-coordinate of the position to project
+ * @param z
+ * the z-coordinate of the position to project
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector3f project(float x, float y, float z, int[] viewport, Vector3f winCoordsDest);
+
+ /**
+ * Project the given position
via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #project(float, float, float, int[], Vector4f)
+ *
+ * @param position
+ * the position to project into window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector4f project(Vector3fc position, int[] viewport, Vector4f winCoordsDest);
+
+ /**
+ * Project the given position
via this
matrix using the specified viewport
+ * and store the resulting window coordinates in winCoordsDest
.
+ *
+ * This method transforms the given coordinates by this
matrix including perspective division to
+ * obtain normalized device coordinates, and then translates these into window coordinates by using the
+ * given viewport
settings [x, y, width, height]
.
+ *
+ * The depth range of the returned winCoordsDest.z
will be [0..1]
, which is also the OpenGL default.
+ *
+ * @see #project(float, float, float, int[], Vector4f)
+ *
+ * @param position
+ * the position to project into window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param winCoordsDest
+ * will hold the projected window coordinates
+ * @return winCoordsDest
+ */
+ Vector3f project(Vector3fc position, int[] viewport, Vector3f winCoordsDest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
and store the result in dest
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f reflect(float a, float b, float c, float d, Matrix4f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f reflect(float nx, float ny, float nz, float px, float py, float pz, Matrix4f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane, and store the result in dest
.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation relative to an implied normal vector of (0, 0, 1)
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f reflect(Quaternionfc orientation, Vector3fc point, Matrix4f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f reflect(Vector3fc normal, Vector3fc point, Matrix4f dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..3]
+ */
+ Vector4f getRow(int row, Vector4f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the first three components of the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param dest
+ * will hold the first three row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..3]
+ */
+ Vector3f getRow(int row, Vector3f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ Vector4f getColumn(int column, Vector4f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the first three components of the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param dest
+ * will hold the first three column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the matrix element value at the given column and row.
+ *
+ * @param column
+ * the colum index in [0..3]
+ * @param row
+ * the row index in [0..3]
+ * @return the element value
+ */
+ float get(int column, int row);
+
+ /**
+ * Get the matrix element value at the given row and column.
+ *
+ * @param row
+ * the row index in [0..3]
+ * @param column
+ * the colum index in [0..3]
+ * @return the element value
+ */
+ float getRowColumn(int row, int column);
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into the upper left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f normal(Matrix4f dest);
+
+ /**
+ * Compute a normal matrix from the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @see Matrix3f#set(Matrix4fc)
+ * @see #get3x3(Matrix3f)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f normal(Matrix3f dest);
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f cofactor3x3(Matrix3f dest);
+
+ /**
+ * Compute the cofactor matrix of the upper left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f cofactor3x3(Matrix4f dest);
+
+ /**
+ * Normalize the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f normalize3x3(Matrix4f dest);
+
+ /**
+ * Normalize the upper left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f normalize3x3(Matrix3f dest);
+
+ /**
+ * Calculate a frustum plane of this
matrix, which
+ * can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given planeEquation
.
+ *
+ * Generally, this method computes the frustum plane in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * The frustum plane will be given in the form of a general plane equation:
+ * a*x + b*y + c*z + d = 0
, where the given {@link Vector4f} components will
+ * hold the (a, b, c, d)
values of the equation.
+ *
+ * The plane normal, which is (a, b, c)
, is directed "inwards" of the frustum.
+ * Any plane/point test using a*x + b*y + c*z + d
therefore will yield a result greater than zero
+ * if the point is within the frustum (i.e. at the positive side of the frustum plane).
+ *
+ * For performing frustum culling, the class {@link FrustumIntersection} should be used instead of
+ * manually obtaining the frustum planes and testing them against points, spheres or axis-aligned boxes.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param plane
+ * one of the six possible planes, given as numeric constants
+ * {@link #PLANE_NX}, {@link #PLANE_PX},
+ * {@link #PLANE_NY}, {@link #PLANE_PY},
+ * {@link #PLANE_NZ} and {@link #PLANE_PZ}
+ * @param planeEquation
+ * will hold the computed plane equation.
+ * The plane equation will be normalized, meaning that (a, b, c)
will be a unit vector
+ * @return planeEquation
+ */
+ Vector4f frustumPlane(int plane, Vector4f planeEquation);
+
+ /**
+ * Compute the corner coordinates of the frustum defined by this
matrix, which
+ * can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given point
.
+ *
+ * Generally, this method computes the frustum corners in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * Reference: http://geomalgorithms.com
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param corner
+ * one of the eight possible corners, given as numeric constants
+ * {@link #CORNER_NXNYNZ}, {@link #CORNER_PXNYNZ}, {@link #CORNER_PXPYNZ}, {@link #CORNER_NXPYNZ},
+ * {@link #CORNER_PXNYPZ}, {@link #CORNER_NXNYPZ}, {@link #CORNER_NXPYPZ}, {@link #CORNER_PXPYPZ}
+ * @param point
+ * will hold the resulting corner point coordinates
+ * @return point
+ */
+ Vector3f frustumCorner(int corner, Vector3f point);
+
+ /**
+ * Compute the eye/origin of the perspective frustum transformation defined by this
matrix,
+ * which can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given origin
.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(float, float, float, float, Matrix4f) perspective()}
+ * or {@link #frustum(float, float, float, float, float, float, Matrix4f) frustum()}.
+ *
+ * Generally, this method computes the origin in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * This method is equivalent to calling: invert(new Matrix4f()).transformProject(0, 0, -1, 0, origin)
+ * and in the case of an already available inverse of this
matrix, the method {@link #perspectiveInvOrigin(Vector3f)}
+ * on the inverse of the matrix should be used instead.
+ *
+ * Reference: http://geomalgorithms.com
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param origin
+ * will hold the origin of the coordinate system before applying this
+ * perspective projection transformation
+ * @return origin
+ */
+ Vector3f perspectiveOrigin(Vector3f origin);
+
+ /**
+ * Compute the eye/origin of the inverse of the perspective frustum transformation defined by this
matrix,
+ * which can be the inverse of a projection matrix or the inverse of a combined modelview-projection matrix, and store the result
+ * in the given dest
.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(float, float, float, float, Matrix4f) perspective()}
+ * or {@link #frustum(float, float, float, float, float, float, Matrix4f) frustum()}.
+ *
+ * If the inverse of the modelview-projection matrix is not available, then calling {@link #perspectiveOrigin(Vector3f)}
+ * on the original modelview-projection matrix is preferred.
+ *
+ * @see #perspectiveOrigin(Vector3f)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f perspectiveInvOrigin(Vector3f dest);
+
+ /**
+ * Return the vertical field-of-view angle in radians of this perspective transformation matrix.
+ *
+ * Note that this method will only work using perspective projections obtained via one of the
+ * perspective methods, such as {@link #perspective(float, float, float, float, Matrix4f) perspective()}
+ * or {@link #frustum(float, float, float, float, float, float, Matrix4f) frustum()}.
+ *
+ * For orthogonal transformations this method will return 0.0
.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @return the vertical field-of-view angle in radians
+ */
+ float perspectiveFov();
+
+ /**
+ * Extract the near clip plane distance from this
perspective projection matrix.
+ *
+ * This method only works if this
is a perspective projection matrix, for example obtained via {@link #perspective(float, float, float, float, Matrix4f)}.
+ *
+ * @return the near clip plane distance
+ */
+ float perspectiveNear();
+
+ /**
+ * Extract the far clip plane distance from this
perspective projection matrix.
+ *
+ * This method only works if this
is a perspective projection matrix, for example obtained via {@link #perspective(float, float, float, float, Matrix4f)}.
+ *
+ * @return the far clip plane distance
+ */
+ float perspectiveFar();
+
+ /**
+ * Obtain the direction of a ray starting at the center of the coordinate system and going
+ * through the near frustum plane.
+ *
+ * This method computes the dir
vector in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * The parameters x
and y
are used to interpolate the generated ray direction
+ * from the bottom-left to the top-right frustum corners.
+ *
+ * For optimal efficiency when building many ray directions over the whole frustum,
+ * it is recommended to use this method only in order to compute the four corner rays at
+ * (0, 0)
, (1, 0)
, (0, 1)
and (1, 1)
+ * and then bilinearly interpolating between them; or to use the {@link FrustumRayBuilder}.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the interpolation factor along the left-to-right frustum planes, within [0..1]
+ * @param y
+ * the interpolation factor along the bottom-to-top frustum planes, within [0..1]
+ * @param dir
+ * will hold the normalized ray direction in the local frame of the coordinate system before
+ * transforming to homogeneous clipping space using this
matrix
+ * @return dir
+ */
+ Vector3f frustumRayDir(float x, float y, Vector3f dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invert();
+ * inv.transformDirection(dir.set(0, 0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveZ(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f positiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).transpose();
+ * inv.transformDirection(dir.set(0, 0, 1));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f normalizedPositiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invert();
+ * inv.transformDirection(dir.set(1, 0, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f positiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).transpose();
+ * inv.transformDirection(dir.set(1, 0, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f normalizedPositiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invert();
+ * inv.transformDirection(dir.set(0, 1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f positiveY(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the upper left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).transpose();
+ * inv.transformDirection(dir.set(0, 1, 0));
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f normalizedPositiveY(Vector3f dir);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
{@link #isAffine() affine} matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method only works with {@link #isAffine() affine} matrices.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invertAffine();
+ * inv.transformPosition(origin.set(0, 0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector3f originAffine(Vector3f origin);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view/projection transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4f inv = new Matrix4f(this).invert();
+ * inv.transformPosition(origin.set(0, 0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector3f origin(Vector3f origin);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f shadow(Vector4f light, float a, float b, float c, float d, Matrix4f dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f shadow(float lightX, float lightY, float lightZ, float lightW, float a, float b, float c, float d, Matrix4f dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f shadow(Vector4f light, Matrix4fc planeTransform, Matrix4f dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f shadow(float lightX, float lightY, float lightZ, float lightW, Matrix4fc planeTransform, Matrix4f dest);
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates, and store the result
+ * in dest
.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4f pick(float x, float y, float width, float height, int[] viewport, Matrix4f dest);
+
+ /**
+ * Determine whether this matrix describes an affine transformation. This is the case iff its last row is equal to (0, 0, 0, 1)
.
+ *
+ * @return true
iff this matrix is affine; false
otherwise
+ */
+ boolean isAffine();
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius, dest).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f arcball(float radius, float centerX, float centerY, float centerZ, float angleX, float angleY, Matrix4f dest);
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f arcball(float radius, Vector3fc center, float angleX, float angleY, Matrix4f dest);
+
+ /**
+ * Compute the axis-aligned bounding box of the frustum described by this
matrix and store the minimum corner
+ * coordinates in the given min
and the maximum corner coordinates in the given max
vector.
+ *
+ * The matrix this
is assumed to be the {@link #invert(Matrix4f) inverse} of the origial view-projection matrix
+ * for which to compute the axis-aligned bounding box in world-space.
+ *
+ * The axis-aligned bounding box of the unit frustum is (-1, -1, -1)
, (1, 1, 1)
.
+ *
+ * @param min
+ * will hold the minimum corner coordinates of the axis-aligned bounding box
+ * @param max
+ * will hold the maximum corner coordinates of the axis-aligned bounding box
+ * @return this
+ */
+ Matrix4f frustumAabb(Vector3f min, Vector3f max);
+
+ /**
+ * Compute the range matrix for the Projected Grid transformation as described in chapter "2.4.2 Creating the range conversion matrix"
+ * of the paper Real-time water rendering - Introducing the projected grid concept
+ * based on the inverse of the view-projection matrix which is assumed to be this
, and store that range matrix into dest
.
+ *
+ * If the projected grid will not be visible then this method returns null
.
+ *
+ * This method uses the y = 0
plane for the projection.
+ *
+ * @param projector
+ * the projector view-projection transformation
+ * @param sLower
+ * the lower (smallest) Y-coordinate which any transformed vertex might have while still being visible on the projected grid
+ * @param sUpper
+ * the upper (highest) Y-coordinate which any transformed vertex might have while still being visible on the projected grid
+ * @param dest
+ * will hold the resulting range matrix
+ * @return the computed range matrix; or null
if the projected grid will not be visible
+ */
+ Matrix4f projectedGridRange(Matrix4fc projector, float sLower, float sUpper, Matrix4f dest);
+
+ /**
+ * Change the near and far clip plane distances of this
perspective frustum transformation matrix
+ * and store the result in dest
.
+ *
+ * This method only works if this
is a perspective projection frustum transformation, for example obtained
+ * via {@link #perspective(float, float, float, float, Matrix4f) perspective()} or {@link #frustum(float, float, float, float, float, float, Matrix4f) frustum()}.
+ *
+ * @see #perspective(float, float, float, float, Matrix4f)
+ * @see #frustum(float, float, float, float, float, float, Matrix4f)
+ *
+ * @param near
+ * the new near clip plane distance
+ * @param far
+ * the new far clip plane distance
+ * @param dest
+ * will hold the resulting matrix
+ * @return dest
+ */
+ Matrix4f perspectiveFrustumSlice(float near, float far, Matrix4f dest);
+
+ /**
+ * Build an ortographic projection transformation that fits the view-projection transformation represented by this
+ * into the given affine view
transformation.
+ *
+ * The transformation represented by this
must be given as the {@link #invert(Matrix4f) inverse} of a typical combined camera view-projection
+ * transformation, whose projection can be either orthographic or perspective.
+ *
+ * The view
must be an {@link #isAffine() affine} transformation which in the application of Cascaded Shadow Maps is usually the light view transformation.
+ * It be obtained via any affine transformation or for example via {@link #lookAt(float, float, float, float, float, float, float, float, float, Matrix4f) lookAt()}.
+ *
+ * Reference: OpenGL SDK - Cascaded Shadow Maps
+ *
+ * @param view
+ * the view transformation to build a corresponding orthographic projection to fit the frustum of this
+ * @param dest
+ * will hold the crop projection transformation
+ * @return dest
+ */
+ Matrix4f orthoCrop(Matrix4fc view, Matrix4f dest);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * by this
{@link #isAffine() affine} matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * Reference: http://dev.theomader.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4f transformAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Vector3f outMin, Vector3f outMax);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner min
and maximum corner max
+ * by this
{@link #isAffine() affine} matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4f transformAab(Vector3fc min, Vector3fc max, Vector3f outMin, Vector3f outMax);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f lerp(Matrix4fc other, float t, Matrix4f dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4f().lookAt(new Vector3f(), new Vector3f(dir).negate(), up).invertAffine(), dest)
+ *
+ * @see #rotateTowards(float, float, float, float, float, float, Matrix4f)
+ *
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateTowards(Vector3fc dir, Vector3fc up, Matrix4f dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mulAffine(new Matrix4f().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invertAffine(), dest)
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc, Matrix4f)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the upper left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the upper left of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order X * Y * Z
to obtain the identical matrix.
+ * This means that calling {@link Matrix4fc#rotateXYZ(float, float, float, Matrix4f)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4f m = ...; // <- matrix only representing rotation
+ * Matrix4f n = new Matrix4f();
+ * n.rotateXYZ(m.getEulerAnglesXYZ(new Vector3f()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3f getEulerAnglesXYZ(Vector3f dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the upper left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the upper left of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order Z * Y * X
to obtain the identical matrix.
+ * This means that calling {@link Matrix4fc#rotateZYX(float, float, float, Matrix4f)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4f m = ...; // <- matrix only representing rotation
+ * Matrix4f n = new Matrix4f();
+ * n.rotateZYX(m.getEulerAnglesZYX(new Vector3f()));
+ *
+ *
+ * Reference: http://nghiaho.com/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3f getEulerAnglesZYX(Vector3f dest);
+
+ /**
+ * Test whether the given point (x, y, z)
is within the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given point with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * When testing multiple points using the same transformation matrix, {@link FrustumIntersection} should be used instead.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the point
+ * @param y
+ * the y-coordinate of the point
+ * @param z
+ * the z-coordinate of the point
+ * @return true
if the given point is inside the frustum; false
otherwise
+ */
+ boolean testPoint(float x, float y, float z);
+
+ /**
+ * Test whether the given sphere is partly or completely within or outside of the frustum defined by this
matrix.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given sphere with the coordinates (x, y, z)
given
+ * in space M
is within the clip space.
+ *
+ * When testing multiple spheres using the same transformation matrix, or more sophisticated/optimized intersection algorithms are required,
+ * {@link FrustumIntersection} should be used instead.
+ *
+ * The algorithm implemented by this method is conservative. This means that in certain circumstances a false positive
+ * can occur, when the method returns true
for spheres that are actually not visible.
+ * See iquilezles.org for an examination of this problem.
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param x
+ * the x-coordinate of the sphere's center
+ * @param y
+ * the y-coordinate of the sphere's center
+ * @param z
+ * the z-coordinate of the sphere's center
+ * @param r
+ * the sphere's radius
+ * @return true
if the given sphere is partly or completely inside the frustum; false
otherwise
+ */
+ boolean testSphere(float x, float y, float z, float r);
+
+ /**
+ * Test whether the given axis-aligned box is partly or completely within or outside of the frustum defined by this
matrix.
+ * The box is specified via its min and max corner coordinates.
+ *
+ * This method assumes this
matrix to be a transformation from any arbitrary coordinate system/space M
+ * into standard OpenGL clip space and tests whether the given axis-aligned box with its minimum corner coordinates (minX, minY, minZ)
+ * and maximum corner coordinates (maxX, maxY, maxZ)
given in space M
is within the clip space.
+ *
+ * When testing multiple axis-aligned boxes using the same transformation matrix, or more sophisticated/optimized intersection algorithms are required,
+ * {@link FrustumIntersection} should be used instead.
+ *
+ * The algorithm implemented by this method is conservative. This means that in certain circumstances a false positive
+ * can occur, when the method returns -1
for boxes that are actually not visible/do not intersect the frustum.
+ * See iquilezles.org for an examination of this problem.
+ *
+ * Reference: Efficient View Frustum Culling
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param minX
+ * the x-coordinate of the minimum corner
+ * @param minY
+ * the y-coordinate of the minimum corner
+ * @param minZ
+ * the z-coordinate of the minimum corner
+ * @param maxX
+ * the x-coordinate of the maximum corner
+ * @param maxY
+ * the y-coordinate of the maximum corner
+ * @param maxZ
+ * the z-coordinate of the maximum corner
+ * @return true
if the axis-aligned box is completely or partly inside of the frustum; false
otherwise
+ */
+ boolean testAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ);
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f obliqueZ(float a, float b, Matrix4f dest);
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector up
, and store the result in dest
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from calling
+ * {@link Matrix4f#setLookAt(Vector3fc, Vector3fc, Vector3fc)} with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector up
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4f withLookAtUp(Vector3fc up, Matrix4f dest);
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector (upX, upY, upZ)
, and store the result in dest
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from calling
+ * {@link Matrix4f#setLookAt(float, float, float, float, float, float, float, float, float)} called with the current
+ * local origin of this matrix (as obtained by {@link #originAffine(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector (upX, upY, upZ)
.
+ *
+ * This method must only be called on {@link #isAffine()} matrices.
+ *
+ * @param upX
+ * the x coordinate of the up vector
+ * @param upY
+ * the y coordinate of the up vector
+ * @param upZ
+ * the z coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4f withLookAtUp(float upX, float upY, float upZ, Matrix4f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapXZY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapXZnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapXnYnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapXnZY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapXnZnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYXZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYXnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYZX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYZnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYnXZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYnXnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYnZX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapYnZnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZXY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZXnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZYX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZYnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZnXY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZnXnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZnYX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapZnYnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXYnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXZY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXZnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXnYZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXnYnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXnZY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnXnZnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYXZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYXnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYZX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYZnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYnXZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYnXnZ(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYnZX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnYnZnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZXY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZXnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZYX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZYnX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZnXY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZnXnY(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZnYX(Matrix4f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f mapnZnYnX(Matrix4f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f negateX(Matrix4f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f negateY(Matrix4f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 0 0 0 1
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f negateZ(Matrix4f dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix4fc m, float delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3d.java
new file mode 100644
index 000000000..d28d634cc
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3d.java
@@ -0,0 +1,10698 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of an affine 4x3 matrix (4 columns, 3 rows) of doubles, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20 m30
+ * m01 m11 m21 m31
+ * m02 m12 m22 m32
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Matrix4x3d implements Externalizable, Cloneable, Matrix4x3dc {
+
+ private static final long serialVersionUID = 1L;
+
+ double m00, m01, m02;
+ double m10, m11, m12;
+ double m20, m21, m22;
+ double m30, m31, m32;
+
+ int properties;
+
+ /**
+ * Create a new {@link Matrix4x3d} and set it to {@link #identity() identity}.
+ */
+ public Matrix4x3d() {
+ m00 = 1.0;
+ m11 = 1.0;
+ m22 = 1.0;
+ properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ }
+
+ /**
+ * Create a new {@link Matrix4x3d} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix4x3dc} to copy the values from
+ */
+ public Matrix4x3d(Matrix4x3dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4x3d} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix4x3fc} to copy the values from
+ */
+ public Matrix4x3d(Matrix4x3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4x3d} by setting its left 3x3 submatrix to the values of the given {@link Matrix3dc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix3dc}
+ */
+ public Matrix4x3d(Matrix3dc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4x3d} by setting its left 3x3 submatrix to the values of the given {@link Matrix3fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix3dc}
+ */
+ public Matrix4x3d(Matrix3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new 4x4 matrix using the supplied double values.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m02
+ * the value of m02
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m12
+ * the value of m12
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ * @param m22
+ * the value of m22
+ * @param m30
+ * the value of m30
+ * @param m31
+ * the value of m31
+ * @param m32
+ * the value of m32
+ */
+ public Matrix4x3d(double m00, double m01, double m02,
+ double m10, double m11, double m12,
+ double m20, double m21, double m22,
+ double m30, double m31, double m32) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ this.m30 = m30;
+ this.m31 = m31;
+ this.m32 = m32;
+ determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4x3d} by reading its 12 double components from the given {@link DoubleBuffer}
+ * at the buffer's current position.
+ *
+ * That DoubleBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link DoubleBuffer} to read the matrix values from
+ */
+ public Matrix4x3d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ determineProperties();
+ }
+
+ /**
+ * Assume the given properties about this matrix.
+ *
+ * Use one or multiple of 0, {@link Matrix4x3dc#PROPERTY_IDENTITY},
+ * {@link Matrix4x3dc#PROPERTY_TRANSLATION}, {@link Matrix4x3dc#PROPERTY_ORTHONORMAL}.
+ *
+ * @param properties
+ * bitset of the properties to assume about this matrix
+ * @return this
+ */
+ public Matrix4x3d assume(int properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ /**
+ * Compute and set the matrix properties returned by {@link #properties()} based
+ * on the current matrix element values.
+ *
+ * @return this
+ */
+ public Matrix4x3d determineProperties() {
+ int properties = 0;
+ if (m00 == 1.0 && m01 == 0.0 && m02 == 0.0 && m10 == 0.0 && m11 == 1.0 && m12 == 0.0
+ && m20 == 0.0 && m21 == 0.0 && m22 == 1.0) {
+ properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ if (m30 == 0.0 && m31 == 0.0 && m32 == 0.0)
+ properties |= PROPERTY_IDENTITY;
+ }
+ /*
+ * We do not determine orthogonality, since it would require arbitrary epsilons
+ * and is rather expensive (6 dot products) in the worst case.
+ */
+ this.properties = properties;
+ return this;
+ }
+
+ public int properties() {
+ return properties;
+ }
+
+ public double m00() {
+ return m00;
+ }
+ public double m01() {
+ return m01;
+ }
+ public double m02() {
+ return m02;
+ }
+ public double m10() {
+ return m10;
+ }
+ public double m11() {
+ return m11;
+ }
+ public double m12() {
+ return m12;
+ }
+ public double m20() {
+ return m20;
+ }
+ public double m21() {
+ return m21;
+ }
+ public double m22() {
+ return m22;
+ }
+ public double m30() {
+ return m30;
+ }
+ public double m31() {
+ return m31;
+ }
+ public double m32() {
+ return m32;
+ }
+
+ Matrix4x3d _properties(int properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m00(double m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m01(double m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m02(double m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m10(double m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m11(double m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m12(double m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m20(double m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m21(double m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m22(double m22) {
+ this.m22 = m22;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m30(double m30) {
+ this.m30 = m30;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m31(double m31) {
+ this.m31 = m31;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ Matrix4x3d _m32(double m32) {
+ this.m32 = m32;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m00(double m00) {
+ this.m00 = m00;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m00 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m01(double m01) {
+ this.m01 = m01;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m01 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m02(double m02) {
+ this.m02 = m02;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m02 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m10(double m10) {
+ this.m10 = m10;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m10 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m11(double m11) {
+ this.m11 = m11;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m11 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m12(double m12) {
+ this.m12 = m12;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m12 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m20(double m20) {
+ this.m20 = m20;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m20 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m21(double m21) {
+ this.m21 = m21;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m21 != 0.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m22(double m22) {
+ this.m22 = m22;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m22 != 1.0)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m30(double m30) {
+ this.m30 = m30;
+ if (m30 != 0.0)
+ properties &= ~PROPERTY_IDENTITY;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m31(double m31) {
+ this.m31 = m31;
+ if (m31 != 0.0)
+ properties &= ~PROPERTY_IDENTITY;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ public Matrix4x3d m32(double m32) {
+ this.m32 = m32;
+ if (m32 != 0.0)
+ properties &= ~PROPERTY_IDENTITY;
+ return this;
+ }
+
+ /**
+ * Reset this matrix to the identity.
+ *
+ * Please note that if a call to {@link #identity()} is immediately followed by a call to:
+ * {@link #translate(double, double, double) translate},
+ * {@link #rotate(double, double, double, double) rotate},
+ * {@link #scale(double, double, double) scale},
+ * {@link #ortho(double, double, double, double, double, double) ortho},
+ * {@link #ortho2D(double, double, double, double) ortho2D},
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt},
+ * {@link #lookAlong(double, double, double, double, double, double) lookAlong},
+ * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with:
+ * {@link #translation(double, double, double) translation},
+ * {@link #rotation(double, double, double, double) rotation},
+ * {@link #scaling(double, double, double) scaling},
+ * {@link #setOrtho(double, double, double, double, double, double) setOrtho},
+ * {@link #setOrtho2D(double, double, double, double) setOrtho2D},
+ * {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt},
+ * {@link #setLookAlong(double, double, double, double, double, double) setLookAlong},
+ * or any of their overloads.
+ *
+ * @return this
+ */
+ public Matrix4x3d identity() {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return this;
+ m00 = 1.0;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 1.0;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4x3d set(Matrix4x3dc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ m30 = m.m30();
+ m31 = m.m31();
+ m32 = m.m32();
+ properties = m.properties();
+ return this;
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4x3d set(Matrix4x3fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ m30 = m.m30();
+ m31 = m.m31();
+ m32 = m.m32();
+ properties = m.properties();
+ return this;
+ }
+
+ /**
+ * Store the values of the upper 4x3 submatrix of m
into this
matrix.
+ *
+ * @see Matrix4dc#get4x3(Matrix4x3d)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4x3d set(Matrix4dc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ m30 = m.m30();
+ m31 = m.m31();
+ m32 = m.m32();
+ properties = m.properties() & (PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ public Matrix4d get(Matrix4d dest) {
+ return dest.set4x3(this);
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3dc}
+ * and the rest to identity.
+ *
+ * @see #Matrix4x3d(Matrix3dc)
+ *
+ * @param mat
+ * the {@link Matrix3dc}
+ * @return this
+ */
+ public Matrix4x3d set(Matrix3dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ return determineProperties();
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3fc}
+ * and the rest to identity.
+ *
+ * @see #Matrix4x3d(Matrix3fc)
+ *
+ * @param mat
+ * the {@link Matrix3fc}
+ * @return this
+ */
+ public Matrix4x3d set(Matrix3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ return determineProperties();
+ }
+
+ /**
+ * Set the four columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ * @return this
+ */
+ public Matrix4x3d set(Vector3dc col0,
+ Vector3dc col1,
+ Vector3dc col2,
+ Vector3dc col3) {
+ this.m00 = col0.x();
+ this.m01 = col0.y();
+ this.m02 = col0.z();
+ this.m10 = col1.x();
+ this.m11 = col1.y();
+ this.m12 = col1.z();
+ this.m20 = col2.x();
+ this.m21 = col2.y();
+ this.m22 = col2.z();
+ this.m30 = col3.x();
+ this.m31 = col3.y();
+ this.m32 = col3.z();
+ return determineProperties();
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3d} to that of the given {@link Matrix4x3dc}
+ * and don't change the other elements.
+ *
+ * @param mat
+ * the {@link Matrix4x3dc}
+ * @return this
+ */
+ public Matrix4x3d set3x3(Matrix4x3dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ properties &= mat.properties();
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Matrix4x3d set(AxisAngle4f axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ m00 = c + x*x*omc;
+ m11 = c + y*y*omc;
+ m22 = c + z*z*omc;
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ m10 = tmp1 - tmp2;
+ m01 = tmp1 + tmp2;
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = tmp1 + tmp2;
+ m02 = tmp1 - tmp2;
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = tmp1 - tmp2;
+ m12 = tmp1 + tmp2;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Matrix4x3d set(AxisAngle4d axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double invLength = Math.invsqrt(x*x + y*y + z*z);
+ x *= invLength;
+ y *= invLength;
+ z *= invLength;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ m00 = c + x*x*omc;
+ m11 = c + y*y*omc;
+ m22 = c + z*z*omc;
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ m10 = tmp1 - tmp2;
+ m01 = tmp1 + tmp2;
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = tmp1 + tmp2;
+ m02 = tmp1 - tmp2;
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = tmp1 - tmp2;
+ m12 = tmp1 + tmp2;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaternionfc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param q
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3d set(Quaternionfc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniondc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * @param q
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4x3d set(Quaterniondc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @return this
+ */
+ public Matrix4x3d mul(Matrix4x3dc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4x3d mul(Matrix4x3dc right, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return mulTranslation(right, dest);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4x3d mulGeneric(Matrix4x3dc right, Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ double m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ double rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ double rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ double rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ double rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._properties(properties & right.properties() & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @return this
+ */
+ public Matrix4x3d mul(Matrix4x3fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4x3d mul(Matrix4x3fc right, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return mulTranslation(right, dest);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4x3d mulGeneric(Matrix4x3fc right, Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ double m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ double rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ double rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ double rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ double rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._properties(properties & right.properties() & PROPERTY_ORTHONORMAL);
+ }
+
+ public Matrix4x3d mulTranslation(Matrix4x3dc right, Matrix4x3d dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._properties(right.properties() & PROPERTY_ORTHONORMAL);
+ }
+
+ public Matrix4x3d mulTranslation(Matrix4x3fc right, Matrix4x3d dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._properties(right.properties() & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied view
matrix.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix which to multiply this
with
+ * @return this
+ */
+ public Matrix4x3d mulOrtho(Matrix4x3dc view) {
+ return mulOrtho(view, this);
+ }
+
+ public Matrix4x3d mulOrtho(Matrix4x3dc view, Matrix4x3d dest) {
+ double nm00 = m00 * view.m00();
+ double nm01 = m11 * view.m01();
+ double nm02 = m22 * view.m02();
+ double nm10 = m00 * view.m10();
+ double nm11 = m11 * view.m11();
+ double nm12 = m22 * view.m12();
+ double nm20 = m00 * view.m20();
+ double nm21 = m11 * view.m21();
+ double nm22 = m22 * view.m22();
+ double nm30 = m00 * view.m30() + m30;
+ double nm31 = m11 * view.m31() + m31;
+ double nm32 = m22 * view.m32() + m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = (this.properties & view.properties() & PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+
+ /**
+ * Multiply this
by the 4x3 matrix with the column vectors (rm00, rm01, rm02)
,
+ * (rm10, rm11, rm12)
, (rm20, rm21, rm22)
and (0, 0, 0)
.
+ *
+ * If M
is this
matrix and R
the specified matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the R
matrix will be applied first!
+ *
+ * @param rm00
+ * the value of the m00 element
+ * @param rm01
+ * the value of the m01 element
+ * @param rm02
+ * the value of the m02 element
+ * @param rm10
+ * the value of the m10 element
+ * @param rm11
+ * the value of the m11 element
+ * @param rm12
+ * the value of the m12 element
+ * @param rm20
+ * the value of the m20 element
+ * @param rm21
+ * the value of the m21 element
+ * @param rm22
+ * the value of the m22 element
+ * @return this
+ */
+ public Matrix4x3d mul3x3(
+ double rm00, double rm01, double rm02,
+ double rm10, double rm11, double rm12,
+ double rm20, double rm21, double rm22) {
+ return mul3x3(rm00, rm01, rm02, rm10, rm11, rm12, rm20, rm21, rm22, this);
+ }
+ public Matrix4x3d mul3x3(
+ double rm00, double rm01, double rm02,
+ double rm10, double rm11, double rm12,
+ double rm20, double rm21, double rm22,
+ Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ double m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._properties(0);
+ }
+
+ /**
+ * Component-wise add this
and other
+ * by first multiplying each component of other
by otherFactor
and
+ * adding that result to this
.
+ *
+ * The matrix other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's components
+ * @return this
+ */
+ public Matrix4x3d fma(Matrix4x3dc other, double otherFactor) {
+ return fma(other, otherFactor, this);
+ }
+
+ public Matrix4x3d fma(Matrix4x3dc other, double otherFactor, Matrix4x3d dest) {
+ dest
+ ._m00(Math.fma(other.m00(), otherFactor, m00))
+ ._m01(Math.fma(other.m01(), otherFactor, m01))
+ ._m02(Math.fma(other.m02(), otherFactor, m02))
+ ._m10(Math.fma(other.m10(), otherFactor, m10))
+ ._m11(Math.fma(other.m11(), otherFactor, m11))
+ ._m12(Math.fma(other.m12(), otherFactor, m12))
+ ._m20(Math.fma(other.m20(), otherFactor, m20))
+ ._m21(Math.fma(other.m21(), otherFactor, m21))
+ ._m22(Math.fma(other.m22(), otherFactor, m22))
+ ._m30(Math.fma(other.m30(), otherFactor, m30))
+ ._m31(Math.fma(other.m31(), otherFactor, m31))
+ ._m32(Math.fma(other.m32(), otherFactor, m32))
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add this
and other
+ * by first multiplying each component of other
by otherFactor
and
+ * adding that result to this
.
+ *
+ * The matrix other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's components
+ * @return this
+ */
+ public Matrix4x3d fma(Matrix4x3fc other, double otherFactor) {
+ return fma(other, otherFactor, this);
+ }
+
+ public Matrix4x3d fma(Matrix4x3fc other, double otherFactor, Matrix4x3d dest) {
+ dest
+ ._m00(Math.fma(other.m00(), otherFactor, m00))
+ ._m01(Math.fma(other.m01(), otherFactor, m01))
+ ._m02(Math.fma(other.m02(), otherFactor, m02))
+ ._m10(Math.fma(other.m10(), otherFactor, m10))
+ ._m11(Math.fma(other.m11(), otherFactor, m11))
+ ._m12(Math.fma(other.m12(), otherFactor, m12))
+ ._m20(Math.fma(other.m20(), otherFactor, m20))
+ ._m21(Math.fma(other.m21(), otherFactor, m21))
+ ._m22(Math.fma(other.m22(), otherFactor, m22))
+ ._m30(Math.fma(other.m30(), otherFactor, m30))
+ ._m31(Math.fma(other.m31(), otherFactor, m31))
+ ._m32(Math.fma(other.m32(), otherFactor, m32))
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4x3d add(Matrix4x3dc other) {
+ return add(other, this);
+ }
+
+ public Matrix4x3d add(Matrix4x3dc other, Matrix4x3d dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m02 = m02 + other.m02();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ dest.m12 = m12 + other.m12();
+ dest.m20 = m20 + other.m20();
+ dest.m21 = m21 + other.m21();
+ dest.m22 = m22 + other.m22();
+ dest.m30 = m30 + other.m30();
+ dest.m31 = m31 + other.m31();
+ dest.m32 = m32 + other.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4x3d add(Matrix4x3fc other) {
+ return add(other, this);
+ }
+
+ public Matrix4x3d add(Matrix4x3fc other, Matrix4x3d dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m02 = m02 + other.m02();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ dest.m12 = m12 + other.m12();
+ dest.m20 = m20 + other.m20();
+ dest.m21 = m21 + other.m21();
+ dest.m22 = m22 + other.m22();
+ dest.m30 = m30 + other.m30();
+ dest.m31 = m31 + other.m31();
+ dest.m32 = m32 + other.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4x3d sub(Matrix4x3dc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix4x3d sub(Matrix4x3dc subtrahend, Matrix4x3d dest) {
+ dest.m00 = m00 - subtrahend.m00();
+ dest.m01 = m01 - subtrahend.m01();
+ dest.m02 = m02 - subtrahend.m02();
+ dest.m10 = m10 - subtrahend.m10();
+ dest.m11 = m11 - subtrahend.m11();
+ dest.m12 = m12 - subtrahend.m12();
+ dest.m20 = m20 - subtrahend.m20();
+ dest.m21 = m21 - subtrahend.m21();
+ dest.m22 = m22 - subtrahend.m22();
+ dest.m30 = m30 - subtrahend.m30();
+ dest.m31 = m31 - subtrahend.m31();
+ dest.m32 = m32 - subtrahend.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4x3d sub(Matrix4x3fc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix4x3d sub(Matrix4x3fc subtrahend, Matrix4x3d dest) {
+ dest.m00 = m00 - subtrahend.m00();
+ dest.m01 = m01 - subtrahend.m01();
+ dest.m02 = m02 - subtrahend.m02();
+ dest.m10 = m10 - subtrahend.m10();
+ dest.m11 = m11 - subtrahend.m11();
+ dest.m12 = m12 - subtrahend.m12();
+ dest.m20 = m20 - subtrahend.m20();
+ dest.m21 = m21 - subtrahend.m21();
+ dest.m22 = m22 - subtrahend.m22();
+ dest.m30 = m30 - subtrahend.m30();
+ dest.m31 = m31 - subtrahend.m31();
+ dest.m32 = m32 - subtrahend.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix4x3d mulComponentWise(Matrix4x3dc other) {
+ return mulComponentWise(other, this);
+ }
+
+ public Matrix4x3d mulComponentWise(Matrix4x3dc other, Matrix4x3d dest) {
+ dest.m00 = m00 * other.m00();
+ dest.m01 = m01 * other.m01();
+ dest.m02 = m02 * other.m02();
+ dest.m10 = m10 * other.m10();
+ dest.m11 = m11 * other.m11();
+ dest.m12 = m12 * other.m12();
+ dest.m20 = m20 * other.m20();
+ dest.m21 = m21 * other.m21();
+ dest.m22 = m22 * other.m22();
+ dest.m30 = m30 * other.m30();
+ dest.m31 = m31 * other.m31();
+ dest.m32 = m32 * other.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied double values. The matrix will look like this:
+ *
+ * m00, m10, m20, m30
+ * m01, m11, m21, m31
+ * m02, m12, m22, m32
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m02
+ * the new value of m02
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m12
+ * the new value of m12
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @param m22
+ * the new value of m22
+ * @param m30
+ * the new value of m30
+ * @param m31
+ * the new value of m31
+ * @param m32
+ * the new value of m32
+ * @return this
+ */
+ public Matrix4x3d set(double m00, double m01, double m02,
+ double m10, double m11, double m12,
+ double m20, double m21, double m22,
+ double m30, double m31, double m32) {
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m20 = m20;
+ this.m30 = m30;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m21 = m21;
+ this.m31 = m31;
+ this.m02 = m02;
+ this.m12 = m12;
+ this.m22 = m22;
+ this.m32 = m32;
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 3, 6, 9
+ * 1, 4, 7, 10
+ * 2, 5, 8, 11
+ *
+ * @see #set(double[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4x3d set(double m[], int off) {
+ m00 = m[off+0];
+ m01 = m[off+1];
+ m02 = m[off+2];
+ m10 = m[off+3];
+ m11 = m[off+4];
+ m12 = m[off+5];
+ m20 = m[off+6];
+ m21 = m[off+7];
+ m22 = m[off+8];
+ m30 = m[off+9];
+ m31 = m[off+10];
+ m32 = m[off+11];
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a double array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 3, 6, 9
+ * 1, 4, 7, 10
+ * 2, 5, 8, 11
+ *
+ * @see #set(double[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4x3d set(double m[]) {
+ return set(m, 0);
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 3, 6, 9
+ * 1, 4, 7, 10
+ * 2, 5, 8, 11
+ *
+ * @see #set(float[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4x3d set(float m[], int off) {
+ m00 = m[off+0];
+ m01 = m[off+1];
+ m02 = m[off+2];
+ m10 = m[off+3];
+ m11 = m[off+4];
+ m12 = m[off+5];
+ m20 = m[off+6];
+ m21 = m[off+7];
+ m22 = m[off+8];
+ m30 = m[off+9];
+ m31 = m[off+10];
+ m32 = m[off+11];
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 3, 6, 9
+ * 1, 4, 7, 10
+ * 2, 5, 8, 11
+ *
+ * @see #set(float[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4x3d set(float m[]) {
+ return set(m, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 double values from the given {@link DoubleBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The DoubleBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the DoubleBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * the DoubleBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 double values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d setFloats(ByteBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d setFloats(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.getf(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 double values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return determineProperties();
+ }
+
+ public double determinant() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * @return this
+ */
+ public Matrix4x3d invert() {
+ return invert(this);
+ }
+
+ public Matrix4x3d invert(Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return invertOrthonormal(dest);
+ return invertGeneric(dest);
+ }
+ private Matrix4x3d invertGeneric(Matrix4x3d dest) {
+ double m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
+ double m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
+ double s = 1.0 / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20);
+ double m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
+ double m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
+ double m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
+ double m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
+ double nm00 = (m11m22 - m12m21) * s;
+ double nm01 = (m21m02 - m22m01) * s;
+ double nm02 = (m12m01 - m11m02) * s;
+ double nm10 = (m12m20 - m10m22) * s;
+ double nm11 = (m22m00 - m20m02) * s;
+ double nm12 = (m10m02 - m12m00) * s;
+ double nm20 = (m10m21 - m11m20) * s;
+ double nm21 = (m20m01 - m21m00) * s;
+ double nm22 = (m11m00 - m10m01) * s;
+ double nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s;
+ double nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
+ double nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = 0;
+ return dest;
+ }
+ private Matrix4x3d invertOrthonormal(Matrix4x3d dest) {
+ double nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
+ double nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
+ double nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
+ double m01 = this.m01;
+ double m02 = this.m02;
+ double m12 = this.m12;
+ dest.m00 = m00;
+ dest.m01 = m10;
+ dest.m02 = m20;
+ dest.m10 = m01;
+ dest.m11 = m11;
+ dest.m12 = m21;
+ dest.m20 = m02;
+ dest.m21 = m12;
+ dest.m22 = m22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = PROPERTY_ORTHONORMAL;
+ return dest;
+ }
+
+ public Matrix4x3d invertOrtho(Matrix4x3d dest) {
+ double invM00 = 1.0 / m00;
+ double invM11 = 1.0 / m11;
+ double invM22 = 1.0 / m22;
+ dest.set(invM00, 0, 0,
+ 0, invM11, 0,
+ 0, 0, invM22,
+ -m30 * invM00, -m31 * invM11, -m32 * invM22);
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Invert this
orthographic projection matrix.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @return this
+ */
+ public Matrix4x3d invertOrtho() {
+ return invertOrtho(this);
+ }
+
+ /**
+ * Transpose only the left 3x3 submatrix of this matrix and set the rest of the matrix elements to identity.
+ *
+ * @return this
+ */
+ public Matrix4x3d transpose3x3() {
+ return transpose3x3(this);
+ }
+
+ public Matrix4x3d transpose3x3(Matrix4x3d dest) {
+ double nm00 = m00;
+ double nm01 = m10;
+ double nm02 = m20;
+ double nm10 = m01;
+ double nm11 = m11;
+ double nm12 = m21;
+ double nm20 = m02;
+ double nm21 = m12;
+ double nm22 = m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.properties = properties;
+ return dest;
+ }
+
+ public Matrix3d transpose3x3(Matrix3d dest) {
+ dest.m00(m00);
+ dest.m01(m10);
+ dest.m02(m20);
+ dest.m10(m01);
+ dest.m11(m11);
+ dest.m12(m21);
+ dest.m20(m02);
+ dest.m21(m12);
+ dest.m22(m22);
+ return dest;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3d translation(double x, double y, double z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this.identity();
+ m30 = x;
+ m31 = y;
+ m32 = z;
+ properties = PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * @param offset
+ * the offsets in x, y and z to translate
+ * @return this
+ */
+ public Matrix4x3d translation(Vector3fc offset) {
+ return translation(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * @param offset
+ * the offsets in x, y and z to translate
+ * @return this
+ */
+ public Matrix4x3d translation(Vector3dc offset) {
+ return translation(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the given values (x, y, z)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(double, double, double)}.
+ * To apply a translation, use {@link #translate(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ * @see #translate(double, double, double)
+ *
+ * @param x
+ * the units to translate in x
+ * @param y
+ * the units to translate in y
+ * @param z
+ * the units to translate in z
+ * @return this
+ */
+ public Matrix4x3d setTranslation(double x, double y, double z) {
+ m30 = x;
+ m31 = y;
+ m32 = z;
+ properties &= ~(PROPERTY_IDENTITY);
+ return this;
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the given values (xyz.x, xyz.y, xyz.z)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(Vector3dc)}.
+ * To apply a translation, use {@link #translate(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ * @see #translate(Vector3dc)
+ *
+ * @param xyz
+ * the units to translate in (x, y, z)
+ * @return this
+ */
+ public Matrix4x3d setTranslation(Vector3dc xyz) {
+ return setTranslation(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ public Vector3d getTranslation(Vector3d dest) {
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ return dest;
+ }
+
+ public Vector3d getScale(Vector3d dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + " " + Runtime.format(m30, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + " " + Runtime.format(m31, formatter) + "\n"
+ + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + " " + Runtime.format(m32, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix4x3dc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix4x3dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix4x3d get(Matrix4x3d dest) {
+ return dest.set(this);
+ }
+
+ public Quaternionf getUnnormalizedRotation(Quaternionf dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaternionf getNormalizedRotation(Quaternionf dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaterniond getNormalizedRotation(Quaterniond dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getFloats(ByteBuffer buffer) {
+ return getFloats(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getFloats(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, index, buffer);
+ return buffer;
+ }
+ public Matrix4x3dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public double[] get(double[] arr, int offset) {
+ arr[offset+0] = m00;
+ arr[offset+1] = m01;
+ arr[offset+2] = m02;
+ arr[offset+3] = m10;
+ arr[offset+4] = m11;
+ arr[offset+5] = m12;
+ arr[offset+6] = m20;
+ arr[offset+7] = m21;
+ arr[offset+8] = m22;
+ arr[offset+9] = m30;
+ arr[offset+10] = m31;
+ arr[offset+11] = m32;
+ return arr;
+ }
+
+ public double[] get(double[] arr) {
+ return get(arr, 0);
+ }
+
+ public float[] get(float[] arr, int offset) {
+ arr[offset+0] = (float)m00;
+ arr[offset+1] = (float)m01;
+ arr[offset+2] = (float)m02;
+ arr[offset+3] = (float)m10;
+ arr[offset+4] = (float)m11;
+ arr[offset+5] = (float)m12;
+ arr[offset+6] = (float)m20;
+ arr[offset+7] = (float)m21;
+ arr[offset+8] = (float)m22;
+ arr[offset+9] = (float)m30;
+ arr[offset+10] = (float)m31;
+ arr[offset+11] = (float)m32;
+ return arr;
+ }
+
+ public float[] get(float[] arr) {
+ return get(arr, 0);
+ }
+
+ public float[] get4x4(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy4x4(this, arr, offset);
+ return arr;
+ }
+
+ public float[] get4x4(float[] arr) {
+ return get4x4(arr, 0);
+ }
+
+ public double[] get4x4(double[] arr, int offset) {
+ MemUtil.INSTANCE.copy4x4(this, arr, offset);
+ return arr;
+ }
+
+ public double[] get4x4(double[] arr) {
+ return get4x4(arr, 0);
+ }
+
+ public DoubleBuffer get4x4(DoubleBuffer buffer) {
+ return get4x4(buffer.position(), buffer);
+ }
+
+ public DoubleBuffer get4x4(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get4x4(ByteBuffer buffer) {
+ return get4x4(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get4x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer getTransposed(DoubleBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public DoubleBuffer getTransposed(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer getTransposed(FloatBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public FloatBuffer getTransposed(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putfTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposedFloats(ByteBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getTransposedFloats(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putfTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public double[] getTransposed(double[] arr, int offset) {
+ arr[offset+0] = m00;
+ arr[offset+1] = m10;
+ arr[offset+2] = m20;
+ arr[offset+3] = m30;
+ arr[offset+4] = m01;
+ arr[offset+5] = m11;
+ arr[offset+6] = m21;
+ arr[offset+7] = m31;
+ arr[offset+8] = m02;
+ arr[offset+9] = m12;
+ arr[offset+10] = m22;
+ arr[offset+11] = m32;
+ return arr;
+ }
+
+ public double[] getTransposed(double[] arr) {
+ return getTransposed(arr, 0);
+ }
+
+ /**
+ * Set all the values within this matrix to 0.
+ *
+ * @return this
+ */
+ public Matrix4x3d zero() {
+ m00 = 0.0;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 0.0;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 0.0;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(double) scale()} instead.
+ *
+ * @see #scale(double)
+ *
+ * @param factor
+ * the scale factor in x, y and z
+ * @return this
+ */
+ public Matrix4x3d scaling(double factor) {
+ return scaling(factor, factor, factor);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @param z
+ * the scale in z
+ * @return this
+ */
+ public Matrix4x3d scaling(double x, double y, double z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ this.identity();
+ m00 = x;
+ m11 = y;
+ m22 = z;
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ properties = one ? PROPERTY_ORTHONORMAL : 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by
+ * xyz.x
, xyz.y
and xyz.z
, respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector3dc) scale()} instead.
+ *
+ * @see #scale(Vector3dc)
+ *
+ * @param xyz
+ * the scale in x, y and z, respectively
+ * @return this
+ */
+ public Matrix4x3d scaling(Vector3dc xyz) {
+ return scaling(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * From Wikipedia
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-coordinate of the axis to rotate about
+ * @param y
+ * the y-coordinate of the axis to rotate about
+ * @param z
+ * the z-coordinate of the axis to rotate about
+ * @return this
+ */
+ public Matrix4x3d rotation(double angle, double x, double y, double z) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotationX(x * angle);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotationY(y * angle);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotationZ(z * angle);
+ return rotationInternal(angle, x, y, z);
+ }
+ private Matrix4x3d rotationInternal(double angle, double x, double y, double z) {
+ double sin = Math.sin(angle);
+ double cos = Math.cosFromSin(sin, angle);
+ double C = 1.0 - cos;
+ double xy = x * y, xz = x * z, yz = y * z;
+ m00 = cos + x * x * C;
+ m01 = xy * C + z * sin;
+ m02 = xz * C - y * sin;
+ m10 = xy * C - z * sin;
+ m11 = cos + y * y * C;
+ m12 = yz * C + x * sin;
+ m20 = xz * C + y * sin;
+ m21 = yz * C - x * sin;
+ m22 = cos + z * z * C;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3d rotationX(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = 1.0;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = cos;
+ m12 = sin;
+ m20 = 0.0;
+ m21 = -sin;
+ m22 = cos;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3d rotationY(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = 0.0;
+ m02 = -sin;
+ m10 = 0.0;
+ m11 = 1.0;
+ m12 = 0.0;
+ m20 = sin;
+ m21 = 0.0;
+ m22 = cos;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3d rotationZ(double ang) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = sin;
+ m02 = 0.0;
+ m10 = -sin;
+ m11 = cos;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3d rotationXYZ(double angleX, double angleY, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm11 = cosX;
+ double nm12 = sinX;
+ double nm21 = m_sinX;
+ double nm22 = cosX;
+ // rotateY
+ double nm00 = cosY;
+ double nm01 = nm21 * m_sinY;
+ double nm02 = nm22 * m_sinY;
+ m20 = sinY;
+ m21 = nm21 * cosY;
+ m22 = nm22 * cosY;
+ // rotateZ
+ m00 = nm00 * cosZ;
+ m01 = nm01 * cosZ + nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ;
+ m11 = nm01 * m_sinZ + nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // set last column to identity
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4x3d rotationZYX(double angleZ, double angleY, double angleX) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = cosZ;
+ double nm01 = sinZ;
+ double nm10 = m_sinZ;
+ double nm11 = cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY;
+ double nm21 = nm01 * sinY;
+ double nm22 = cosY;
+ m00 = nm00 * cosY;
+ m01 = nm01 * cosY;
+ m02 = m_sinY;
+ // rotateX
+ m10 = nm10 * cosX + nm20 * sinX;
+ m11 = nm11 * cosX + nm21 * sinX;
+ m12 = nm22 * sinX;
+ m20 = nm10 * m_sinX + nm20 * cosX;
+ m21 = nm11 * m_sinX + nm21 * cosX;
+ m22 = nm22 * cosX;
+ // set last column to identity
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3d rotationYXZ(double angleY, double angleX, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm00 = cosY;
+ double nm02 = m_sinY;
+ double nm20 = sinY;
+ double nm22 = cosY;
+ // rotateX
+ double nm10 = nm20 * sinX;
+ double nm11 = cosX;
+ double nm12 = nm22 * sinX;
+ m20 = nm20 * cosX;
+ m21 = m_sinX;
+ m22 = nm22 * cosX;
+ // rotateZ
+ m00 = nm00 * cosZ + nm10 * sinZ;
+ m01 = nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ + nm10 * cosZ;
+ m11 = nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // set last column to identity
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set only the left 3x3 submatrix of this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3d setRotationXYZ(double angleX, double angleY, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm11 = cosX;
+ double nm12 = sinX;
+ double nm21 = m_sinX;
+ double nm22 = cosX;
+ // rotateY
+ double nm00 = cosY;
+ double nm01 = nm21 * m_sinY;
+ double nm02 = nm22 * m_sinY;
+ m20 = sinY;
+ m21 = nm21 * cosY;
+ m22 = nm22 * cosY;
+ // rotateZ
+ m00 = nm00 * cosZ;
+ m01 = nm01 * cosZ + nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ;
+ m11 = nm01 * m_sinZ + nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set only the left 3x3 submatrix of this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4x3d setRotationZYX(double angleZ, double angleY, double angleX) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = cosZ;
+ double nm01 = sinZ;
+ double nm10 = m_sinZ;
+ double nm11 = cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY;
+ double nm21 = nm01 * sinY;
+ double nm22 = cosY;
+ m00 = nm00 * cosY;
+ m01 = nm01 * cosY;
+ m02 = m_sinY;
+ // rotateX
+ m10 = nm10 * cosX + nm20 * sinX;
+ m11 = nm11 * cosX + nm21 * sinX;
+ m12 = nm22 * sinX;
+ m20 = nm10 * m_sinX + nm20 * cosX;
+ m21 = nm11 * m_sinX + nm21 * cosX;
+ m22 = nm22 * cosX;
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set only the left 3x3 submatrix of this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3d setRotationYXZ(double angleY, double angleX, double angleZ) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm00 = cosY;
+ double nm02 = m_sinY;
+ double nm20 = sinY;
+ double nm22 = cosY;
+ // rotateX
+ double nm10 = nm20 * sinX;
+ double nm11 = cosX;
+ double nm12 = nm22 * sinX;
+ m20 = nm20 * cosX;
+ m21 = m_sinX;
+ m22 = nm22 * cosX;
+ // rotateZ
+ m00 = nm00 * cosZ + nm10 * sinZ;
+ m01 = nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ + nm10 * cosZ;
+ m11 = nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about
+ * @return this
+ */
+ public Matrix4x3d rotation(double angle, Vector3dc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about
+ * @return this
+ */
+ public Matrix4x3d rotation(double angle, Vector3fc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ public Vector4d transform(Vector4d v) {
+ return v.mul(this);
+ }
+
+ public Vector4d transform(Vector4dc v, Vector4d dest) {
+ return v.mul(this, dest);
+ }
+
+ public Vector3d transformPosition(Vector3d v) {
+ v.set(m00 * v.x + m10 * v.y + m20 * v.z + m30,
+ m01 * v.x + m11 * v.y + m21 * v.z + m31,
+ m02 * v.x + m12 * v.y + m22 * v.z + m32);
+ return v;
+ }
+
+ public Vector3d transformPosition(Vector3dc v, Vector3d dest) {
+ dest.set(m00 * v.x() + m10 * v.y() + m20 * v.z() + m30,
+ m01 * v.x() + m11 * v.y() + m21 * v.z() + m31,
+ m02 * v.x() + m12 * v.y() + m22 * v.z() + m32);
+ return dest;
+ }
+
+ public Vector3d transformDirection(Vector3d v) {
+ v.set(m00 * v.x + m10 * v.y + m20 * v.z,
+ m01 * v.x + m11 * v.y + m21 * v.z,
+ m02 * v.x + m12 * v.y + m22 * v.z);
+ return v;
+ }
+
+ public Vector3d transformDirection(Vector3dc v, Vector3d dest) {
+ dest.set(m00 * v.x() + m10 * v.y() + m20 * v.z(),
+ m01 * v.x() + m11 * v.y() + m21 * v.z(),
+ m02 * v.x() + m12 * v.y() + m22 * v.z());
+ return dest;
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3dc} and don't change the other elements.
+ *
+ * @param mat
+ * the 3x3 matrix
+ * @return this
+ */
+ public Matrix4x3d set3x3(Matrix3dc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3d} to the given {@link Matrix3fc} and don't change the other elements.
+ *
+ * @param mat
+ * the 3x3 matrix
+ * @return this
+ */
+ public Matrix4x3d set3x3(Matrix3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ properties = 0;
+ return this;
+ }
+
+ public Matrix4x3d scale(Vector3dc xyz, Matrix4x3d dest) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @return this
+ */
+ public Matrix4x3d scale(Vector3dc xyz) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), this);
+ }
+
+ public Matrix4x3d scale(double x, double y, double z, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ return scaleGeneric(x, y, z, dest);
+ }
+ private Matrix4x3d scaleGeneric(double x, double y, double z, Matrix4x3d dest) {
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m02 = m02 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ dest.m12 = m12 * y;
+ dest.m20 = m20 * z;
+ dest.m21 = m21 * z;
+ dest.m22 = m22 * z;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4x3d scale(double x, double y, double z) {
+ return scale(x, y, z, this);
+ }
+
+ public Matrix4x3d scale(double xyz, Matrix4x3d dest) {
+ return scale(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, double)
+ *
+ * @param xyz
+ * the factor for all components
+ * @return this
+ */
+ public Matrix4x3d scale(double xyz) {
+ return scale(xyz, xyz, xyz);
+ }
+
+ public Matrix4x3d scaleXY(double x, double y, Matrix4x3d dest) {
+ return scale(x, y, 1.0, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the X axis by x
and the Y axis by y
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix4x3d scaleXY(double x, double y) {
+ return scale(x, y, 1.0);
+ }
+
+ public Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4x3d dest) {
+ double nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ double nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ double nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return dest
+ ._m00(m00 * sx)
+ ._m01(m01 * sx)
+ ._m02(m02 * sx)
+ ._m10(m10 * sy)
+ ._m11(m11 * sy)
+ ._m12(m12 * sy)
+ ._m20(m20 * sz)
+ ._m21(m21 * sz)
+ ._m22(m22 * sz)
+ ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30)
+ ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31)
+ ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz) {
+ return scaleAround(sx, sy, sz, ox, oy, oz, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4x3d scaleAround(double factor, double ox, double oy, double oz) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, this);
+ }
+
+ public Matrix4x3d scaleAround(double factor, double ox, double oy, double oz, Matrix4x3d dest) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, dest);
+ }
+
+ public Matrix4x3d scaleLocal(double x, double y, double z, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+
+ double nm00 = x * m00;
+ double nm01 = y * m01;
+ double nm02 = z * m02;
+ double nm10 = x * m10;
+ double nm11 = y * m11;
+ double nm12 = z * m12;
+ double nm20 = x * m20;
+ double nm21 = y * m21;
+ double nm22 = z * m22;
+ double nm30 = x * m30;
+ double nm31 = y * m31;
+ double nm32 = z * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4x3d scaleLocal(double x, double y, double z) {
+ return scaleLocal(x, y, z, this);
+ }
+
+ public Matrix4x3d rotate(double ang, double x, double y, double z, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(ang, x, y, z);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(ang, x, y, z, dest);
+ return rotateGeneric(ang, x, y, z, dest);
+ }
+ private Matrix4x3d rotateGeneric(double ang, double x, double y, double z, Matrix4x3d dest) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateX(x * ang, dest);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateY(y * ang, dest);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateZ(z * ang, dest);
+ return rotateGenericInternal(ang, x, y, z, dest);
+ }
+ private Matrix4x3d rotateGenericInternal(double ang, double x, double y, double z, Matrix4x3d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double rm00 = xx * C + c;
+ double rm01 = xy * C + z * s;
+ double rm02 = xz * C - y * s;
+ double rm10 = xy * C - z * s;
+ double rm11 = yy * C + c;
+ double rm12 = yz * C + x * s;
+ double rm20 = xz * C + y * s;
+ double rm21 = yz * C - x * s;
+ double rm22 = zz * C + c;
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle is in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4x3d rotate(double ang, double x, double y, double z) {
+ return rotate(ang, x, y, z, this);
+ }
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateTranslation(double ang, double x, double y, double z, Matrix4x3d dest) {
+ double tx = m30, ty = m31, tz = m32;
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return dest.rotationX(x * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return dest.rotationY(y * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return dest.rotationZ(z * ang).setTranslation(tx, ty, tz);
+ return rotateTranslationInternal(ang, x, y, z, dest);
+ }
+ private Matrix4x3d rotateTranslationInternal(double ang, double x, double y, double z, Matrix4x3d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double rm00 = xx * C + c;
+ double rm01 = xy * C + z * s;
+ double rm02 = xz * C - y * s;
+ double rm10 = xy * C - z * s;
+ double rm11 = yy * C + c;
+ double rm12 = yz * C + x * s;
+ double rm20 = xz * C + y * s;
+ double rm21 = yz * C - x * s;
+ double rm22 = zz * C + c;
+ double nm00 = rm00;
+ double nm01 = rm01;
+ double nm02 = rm02;
+ double nm10 = rm10;
+ double nm11 = rm11;
+ double nm12 = rm12;
+ // set non-dependent values directly
+ dest.m20 = rm20;
+ dest.m21 = rm21;
+ dest.m22 = rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaterniondc} to this matrix while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4x3d rotateAround(Quaterniondc quat, double ox, double oy, double oz) {
+ return rotateAround(quat, ox, oy, oz, this);
+ }
+
+ private Matrix4x3d rotateAroundAffine(Quaterniondc quat, double ox, double oy, double oz, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = dxy - dzw;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ double tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ double tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
+ ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
+ ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ public Matrix4x3d rotateAround(Quaterniondc quat, double ox, double oy, double oz, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return rotationAround(quat, ox, oy, oz);
+ return rotateAroundAffine(quat, ox, oy, oz, dest);
+ }
+
+ /**
+ * Set this matrix to a transformation composed of a rotation of the specified {@link Quaterniondc} while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4x3d rotationAround(Quaterniondc quat, double ox, double oy, double oz) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ this._m20(dyw + dxz);
+ this._m21(dyz - dxw);
+ this._m22(z2 - y2 - x2 + w2);
+ this._m00(w2 + x2 - z2 - y2);
+ this._m01(dxy + dzw);
+ this._m02(dxz - dyw);
+ this._m10(dxy - dzw);
+ this._m11(y2 - z2 + w2 - x2);
+ this._m12(dyz + dxw);
+ this._m30(-m00 * ox - m10 * oy - m20 * oz + ox);
+ this._m31(-m01 * ox - m11 * oy - m21 * oz + oy);
+ this._m32(-m02 * ox - m12 * oy - m22 * oz + oz);
+ this.properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateLocal(double ang, double x, double y, double z, Matrix4x3d dest) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateLocalX(x * ang, dest);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateLocalY(y * ang, dest);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateLocalZ(z * ang, dest);
+ return rotateLocalInternal(ang, x, y, z, dest);
+ }
+ private Matrix4x3d rotateLocalInternal(double ang, double x, double y, double z, Matrix4x3d dest) {
+ double s = Math.sin(ang);
+ double c = Math.cosFromSin(s, ang);
+ double C = 1.0 - c;
+ double xx = x * x, xy = x * y, xz = x * z;
+ double yy = y * y, yz = y * z;
+ double zz = z * z;
+ double lm00 = xx * C + c;
+ double lm01 = xy * C + z * s;
+ double lm02 = xz * C - y * s;
+ double lm10 = xy * C - z * s;
+ double lm11 = yy * C + c;
+ double lm12 = yz * C + x * s;
+ double lm20 = xz * C + y * s;
+ double lm21 = yz * C - x * s;
+ double lm22 = zz * C + c;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(double, double, double, double) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(double, double, double, double)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4x3d rotateLocal(double ang, double x, double y, double z) {
+ return rotateLocal(ang, x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(double) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateLocalX(double ang, Matrix4x3d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm01 = cos * m01 - sin * m02;
+ double nm02 = sin * m01 + cos * m02;
+ double nm11 = cos * m11 - sin * m12;
+ double nm12 = sin * m11 + cos * m12;
+ double nm21 = cos * m21 - sin * m22;
+ double nm22 = sin * m21 + cos * m22;
+ double nm31 = cos * m31 - sin * m32;
+ double nm32 = sin * m31 + cos * m32;
+ dest.m00 = m00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = m20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = m30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(double) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix4x3d rotateLocalX(double ang) {
+ return rotateLocalX(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateLocalY(double ang, Matrix4x3d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm00 = cos * m00 + sin * m02;
+ double nm02 = -sin * m00 + cos * m02;
+ double nm10 = cos * m10 + sin * m12;
+ double nm12 = -sin * m10 + cos * m12;
+ double nm20 = cos * m20 + sin * m22;
+ double nm22 = -sin * m20 + cos * m22;
+ double nm30 = cos * m30 + sin * m32;
+ double nm32 = -sin * m30 + cos * m32;
+ dest.m00 = nm00;
+ dest.m01 = m01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = m11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = m21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = m31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @return this
+ */
+ public Matrix4x3d rotateLocalY(double ang) {
+ return rotateLocalY(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(double) rotationZ()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationZ(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateLocalZ(double ang, Matrix4x3d dest) {
+ double sin = Math.sin(ang);
+ double cos = Math.cosFromSin(sin, ang);
+ double nm00 = cos * m00 - sin * m01;
+ double nm01 = sin * m00 + cos * m01;
+ double nm10 = cos * m10 - sin * m11;
+ double nm11 = sin * m10 + cos * m11;
+ double nm20 = cos * m20 - sin * m21;
+ double nm21 = sin * m20 + cos * m21;
+ double nm30 = cos * m30 - sin * m31;
+ double nm31 = sin * m30 + cos * m31;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = m02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = m12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = m22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(double) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(double)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @return this
+ */
+ public Matrix4x3d rotateLocalZ(double ang) {
+ return rotateLocalZ(ang, this);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4x3d translate(Vector3dc offset) {
+ return translate(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d translate(Vector3dc offset, Matrix4x3d dest) {
+ return translate(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4x3d translate(Vector3fc offset) {
+ return translate(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d translate(Vector3fc offset, Matrix4x3d dest) {
+ return translate(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d translate(double x, double y, double z, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.translation(x, y, z);
+ return translateGeneric(x, y, z, dest);
+ }
+ private Matrix4x3d translateGeneric(double x, double y, double z, Matrix4x3d dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m30 = m00 * x + m10 * y + m20 * z + m30;
+ dest.m31 = m01 * x + m11 * y + m21 * z + m31;
+ dest.m32 = m02 * x + m12 * y + m22 * z + m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY);
+ return dest;
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3d translate(double x, double y, double z) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return translation(x, y, z);
+ Matrix4x3d c = this;
+ c.m30 = c.m00 * x + c.m10 * y + c.m20 * z + c.m30;
+ c.m31 = c.m01 * x + c.m11 * y + c.m21 * z + c.m31;
+ c.m32 = c.m02 * x + c.m12 * y + c.m22 * z + c.m32;
+ c.properties &= ~(PROPERTY_IDENTITY);
+ return this;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4x3d translateLocal(Vector3fc offset) {
+ return translateLocal(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d translateLocal(Vector3fc offset, Matrix4x3d dest) {
+ return translateLocal(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4x3d translateLocal(Vector3dc offset) {
+ return translateLocal(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3dc)}.
+ *
+ * @see #translation(Vector3dc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d translateLocal(Vector3dc offset, Matrix4x3d dest) {
+ return translateLocal(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d translateLocal(double x, double y, double z, Matrix4x3d dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m30 = m30 + x;
+ dest.m31 = m31 + y;
+ dest.m32 = m32 + z;
+ dest.properties = properties & ~(PROPERTY_IDENTITY);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(double, double, double)}.
+ *
+ * @see #translation(double, double, double)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3d translateLocal(double x, double y, double z) {
+ return translateLocal(x, y, z, this);
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(m00);
+ out.writeDouble(m01);
+ out.writeDouble(m02);
+ out.writeDouble(m10);
+ out.writeDouble(m11);
+ out.writeDouble(m12);
+ out.writeDouble(m20);
+ out.writeDouble(m21);
+ out.writeDouble(m22);
+ out.writeDouble(m30);
+ out.writeDouble(m31);
+ out.writeDouble(m32);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readDouble();
+ m01 = in.readDouble();
+ m02 = in.readDouble();
+ m10 = in.readDouble();
+ m11 = in.readDouble();
+ m12 = in.readDouble();
+ m20 = in.readDouble();
+ m21 = in.readDouble();
+ m22 = in.readDouble();
+ m30 = in.readDouble();
+ m31 = in.readDouble();
+ m32 = in.readDouble();
+ determineProperties();
+ }
+
+ public Matrix4x3d rotateX(double ang, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationX(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double x = m30, y = m31, z = m32;
+ return dest.rotationX(ang).setTranslation(x, y, z);
+ }
+ return rotateXInternal(ang, dest);
+ }
+ private Matrix4x3d rotateXInternal(double ang, Matrix4x3d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm11 = cos;
+ double rm12 = sin;
+ double rm21 = -sin;
+ double rm22 = cos;
+
+ // add temporaries for dependent values
+ double nm10 = m10 * rm11 + m20 * rm12;
+ double nm11 = m11 * rm11 + m21 * rm12;
+ double nm12 = m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m10 * rm21 + m20 * rm22;
+ dest.m21 = m11 * rm21 + m21 * rm22;
+ dest.m22 = m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3d rotateX(double ang) {
+ return rotateX(ang, this);
+ }
+
+ public Matrix4x3d rotateY(double ang, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationY(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double x = m30, y = m31, z = m32;
+ return dest.rotationY(ang).setTranslation(x, y, z);
+ }
+ return rotateYInternal(ang, dest);
+ }
+ private Matrix4x3d rotateYInternal(double ang, Matrix4x3d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm00 = cos;
+ double rm02 = -sin;
+ double rm20 = sin;
+ double rm22 = cos;
+
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m20 * rm02;
+ double nm01 = m01 * rm00 + m21 * rm02;
+ double nm02 = m02 * rm00 + m22 * rm02;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3d rotateY(double ang) {
+ return rotateY(ang, this);
+ }
+
+ public Matrix4x3d rotateZ(double ang, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZ(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double x = m30, y = m31, z = m32;
+ return dest.rotationZ(ang).setTranslation(x, y, z);
+ }
+ return rotateZInternal(ang, dest);
+ }
+ private Matrix4x3d rotateZInternal(double ang, Matrix4x3d dest) {
+ double sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ double rm00 = cos;
+ double rm01 = sin;
+ double rm10 = -sin;
+ double rm11 = cos;
+
+ // add temporaries for dependent values
+ double nm00 = m00 * rm00 + m10 * rm01;
+ double nm01 = m01 * rm00 + m11 * rm01;
+ double nm02 = m02 * rm00 + m12 * rm01;
+ // set non-dependent values directly
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m12 = m02 * rm10 + m12 * rm11;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3d rotateZ(double ang) {
+ return rotateZ(ang, this);
+ }
+
+ /**
+ * Apply rotation of angles.x
radians about the X axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4x3d rotateXYZ(Vector3d angles) {
+ return rotateXYZ(angles.x, angles.y, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationXYZ(angleX, angleY, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
+ }
+ return rotateXYZInternal(angleX, angleY, angleZ, dest);
+ }
+ private Matrix4x3d rotateXYZInternal(double angleX, double angleY, double angleZ, Matrix4x3d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinX = -sinX;
+ double m_sinY = -sinY;
+ double m_sinZ = -sinZ;
+
+ // rotateX
+ double nm10 = m10 * cosX + m20 * sinX;
+ double nm11 = m11 * cosX + m21 * sinX;
+ double nm12 = m12 * cosX + m22 * sinX;
+ double nm20 = m10 * m_sinX + m20 * cosX;
+ double nm21 = m11 * m_sinX + m21 * cosX;
+ double nm22 = m12 * m_sinX + m22 * cosX;
+ // rotateY
+ double nm00 = m00 * cosY + nm20 * m_sinY;
+ double nm01 = m01 * cosY + nm21 * m_sinY;
+ double nm02 = m02 * cosY + nm22 * m_sinY;
+ dest.m20 = m00 * sinY + nm20 * cosY;
+ dest.m21 = m01 * sinY + nm21 * cosY;
+ dest.m22 = m02 * sinY + nm22 * cosY;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // copy last column from 'this'
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.z
radians about the Z axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.x
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4x3d rotateZYX(Vector3d angles) {
+ return rotateZYX(angles.z, angles.y, angles.x);
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZYX(angleZ, angleY, angleX);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz);
+ }
+ return rotateZYXInternal(angleZ, angleY, angleX, dest);
+ }
+ private Matrix4x3d rotateZYXInternal(double angleZ, double angleY, double angleX, Matrix4x3d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinZ = -sinZ;
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+
+ // rotateZ
+ double nm00 = m00 * cosZ + m10 * sinZ;
+ double nm01 = m01 * cosZ + m11 * sinZ;
+ double nm02 = m02 * cosZ + m12 * sinZ;
+ double nm10 = m00 * m_sinZ + m10 * cosZ;
+ double nm11 = m01 * m_sinZ + m11 * cosZ;
+ double nm12 = m02 * m_sinZ + m12 * cosZ;
+ // rotateY
+ double nm20 = nm00 * sinY + m20 * cosY;
+ double nm21 = nm01 * sinY + m21 * cosY;
+ double nm22 = nm02 * sinY + m22 * cosY;
+ dest.m00 = nm00 * cosY + m20 * m_sinY;
+ dest.m01 = nm01 * cosY + m21 * m_sinY;
+ dest.m02 = nm02 * cosY + m22 * m_sinY;
+ // rotateX
+ dest.m10 = nm10 * cosX + nm20 * sinX;
+ dest.m11 = nm11 * cosX + nm21 * sinX;
+ dest.m12 = nm12 * cosX + nm22 * sinX;
+ dest.m20 = nm10 * m_sinX + nm20 * cosX;
+ dest.m21 = nm11 * m_sinX + nm21 * cosX;
+ dest.m22 = nm12 * m_sinX + nm22 * cosX;
+ // copy last column from 'this'
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.y
radians about the Y axis, followed by a rotation of angles.x
radians about the X axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4x3d rotateYXZ(Vector3d angles) {
+ return rotateYXZ(angles.y, angles.x, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationYXZ(angleY, angleX, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ double tx = m30, ty = m31, tz = m32;
+ return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz);
+ }
+ return rotateYXZInternal(angleY, angleX, angleZ, dest);
+ }
+ private Matrix4x3d rotateYXZInternal(double angleY, double angleX, double angleZ, Matrix4x3d dest) {
+ double sinX = Math.sin(angleX);
+ double cosX = Math.cosFromSin(sinX, angleX);
+ double sinY = Math.sin(angleY);
+ double cosY = Math.cosFromSin(sinY, angleY);
+ double sinZ = Math.sin(angleZ);
+ double cosZ = Math.cosFromSin(sinZ, angleZ);
+ double m_sinY = -sinY;
+ double m_sinX = -sinX;
+ double m_sinZ = -sinZ;
+
+ // rotateY
+ double nm20 = m00 * sinY + m20 * cosY;
+ double nm21 = m01 * sinY + m21 * cosY;
+ double nm22 = m02 * sinY + m22 * cosY;
+ double nm00 = m00 * cosY + m20 * m_sinY;
+ double nm01 = m01 * cosY + m21 * m_sinY;
+ double nm02 = m02 * cosY + m22 * m_sinY;
+ // rotateX
+ double nm10 = m10 * cosX + nm20 * sinX;
+ double nm11 = m11 * cosX + nm21 * sinX;
+ double nm12 = m12 * cosX + nm22 * sinX;
+ dest.m20 = m10 * m_sinX + nm20 * cosX;
+ dest.m21 = m11 * m_sinX + nm21 * cosX;
+ dest.m22 = m12 * m_sinX + nm22 * cosX;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // copy last column from 'this'
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4f) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4f)
+ *
+ * @param angleAxis
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d rotation(AxisAngle4f angleAxis) {
+ return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4d}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4d) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4d)
+ *
+ * @param angleAxis
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d rotation(AxisAngle4d angleAxis) {
+ return rotation(angleAxis.angle, angleAxis.x, angleAxis.y, angleAxis.z);
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaterniondc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaterniondc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4x3d rotation(Quaterniondc quat) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw;
+ double xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz;
+ double yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz;
+ double xw = quat.x() * quat.w(), dxw = xw + xw;
+ _m00(w2 + x2 - z2 - y2);
+ _m01(dxy + dzw);
+ _m02(dxz - dyw);
+ _m10(dxy - dzw);
+ _m11(y2 - z2 + w2 - x2);
+ _m12(dyz + dxw);
+ _m20(dyw + dxz);
+ _m21(dyz - dxw);
+ _m22(z2 - y2 - x2 + w2);
+ _m30(0.0);
+ _m31(0.0);
+ _m32(0.0);
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaternionfc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaternionfc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3d rotation(Quaternionfc quat) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw;
+ double xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz;
+ double yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz;
+ double xw = quat.x() * quat.w(), dxw = xw + xw;
+ _m00(w2 + x2 - z2 - y2);
+ _m01(dxy + dzw);
+ _m02(dxz - dyw);
+ _m10(dxy - dzw);
+ _m11(y2 - z2 + w2 - x2);
+ _m12(dyz + dxw);
+ _m20(dyw + dxz);
+ _m21(dyz - dxw);
+ _m22(z2 - y2 - x2 + w2);
+ _m30(0.0);
+ _m31(0.0);
+ _m32(0.0);
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(double, double, double)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @return this
+ */
+ public Matrix4x3d translationRotateScale(double tx, double ty, double tz,
+ double qx, double qy, double qz, double qw,
+ double sx, double sy, double sz) {
+ double dqx = qx + qx, dqy = qy + qy, dqz = qz + qz;
+ double q00 = dqx * qx;
+ double q11 = dqy * qy;
+ double q22 = dqz * qz;
+ double q01 = dqx * qy;
+ double q02 = dqx * qz;
+ double q03 = dqx * qw;
+ double q12 = dqy * qz;
+ double q13 = dqy * qw;
+ double q23 = dqz * qw;
+ m00 = sx - (q11 + q22) * sx;
+ m01 = (q01 + q23) * sx;
+ m02 = (q02 - q13) * sx;
+ m10 = (q01 - q23) * sy;
+ m11 = sy - (q22 + q00) * sy;
+ m12 = (q12 + q03) * sy;
+ m20 = (q02 + q13) * sz;
+ m21 = (q12 - q03) * sz;
+ m22 = sz - (q11 + q00) * sz;
+ m30 = tx;
+ m31 = ty;
+ m32 = tz;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4x3d translationRotateScale(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3dc)
+ * @see #rotate(Quaterniondc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4x3d translationRotateScale(Vector3dc translation,
+ Quaterniondc quat,
+ Vector3dc scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mul(m)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ * @see #scale(double, double, double)
+ * @see #mul(Matrix4x3dc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @param m
+ * the matrix to multiply by
+ * @return this
+ */
+ public Matrix4x3d translationRotateScaleMul(
+ double tx, double ty, double tz,
+ double qx, double qy, double qz, double qw,
+ double sx, double sy, double sz,
+ Matrix4x3dc m) {
+ double dqx = qx + qx;
+ double dqy = qy + qy;
+ double dqz = qz + qz;
+ double q00 = dqx * qx;
+ double q11 = dqy * qy;
+ double q22 = dqz * qz;
+ double q01 = dqx * qy;
+ double q02 = dqx * qz;
+ double q03 = dqx * qw;
+ double q12 = dqy * qz;
+ double q13 = dqy * qw;
+ double q23 = dqz * qw;
+ double nm00 = sx - (q11 + q22) * sx;
+ double nm01 = (q01 + q23) * sx;
+ double nm02 = (q02 - q13) * sx;
+ double nm10 = (q01 - q23) * sy;
+ double nm11 = sy - (q22 + q00) * sy;
+ double nm12 = (q12 + q03) * sy;
+ double nm20 = (q02 + q13) * sz;
+ double nm21 = (q12 - q03) * sz;
+ double nm22 = sz - (q11 + q00) * sz;
+ double m00 = nm00 * m.m00() + nm10 * m.m01() + nm20 * m.m02();
+ double m01 = nm01 * m.m00() + nm11 * m.m01() + nm21 * m.m02();
+ m02 = nm02 * m.m00() + nm12 * m.m01() + nm22 * m.m02();
+ this.m00 = m00;
+ this.m01 = m01;
+ double m10 = nm00 * m.m10() + nm10 * m.m11() + nm20 * m.m12();
+ double m11 = nm01 * m.m10() + nm11 * m.m11() + nm21 * m.m12();
+ m12 = nm02 * m.m10() + nm12 * m.m11() + nm22 * m.m12();
+ this.m10 = m10;
+ this.m11 = m11;
+ double m20 = nm00 * m.m20() + nm10 * m.m21() + nm20 * m.m22();
+ double m21 = nm01 * m.m20() + nm11 * m.m21() + nm21 * m.m22();
+ m22 = nm02 * m.m20() + nm12 * m.m21() + nm22 * m.m22();
+ this.m20 = m20;
+ this.m21 = m21;
+ double m30 = nm00 * m.m30() + nm10 * m.m31() + nm20 * m.m32() + tx;
+ double m31 = nm01 * m.m30() + nm11 * m.m31() + nm21 * m.m32() + ty;
+ m32 = nm02 * m.m30() + nm12 * m.m31() + nm22 * m.m32() + tz;
+ this.m30 = m30;
+ this.m31 = m31;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale).mul(m)
+ *
+ * @see #translation(Vector3dc)
+ * @see #rotate(Quaterniondc)
+ * @see #mul(Matrix4x3dc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @param m
+ * the matrix to multiply by
+ * @return this
+ */
+ public Matrix4x3d translationRotateScaleMul(Vector3dc translation, Quaterniondc quat, Vector3dc scale, Matrix4x3dc m) {
+ return translationRotateScaleMul(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z(), m);
+ }
+
+ /**
+ * Set this
matrix to T * R
, where T
is a translation by the given (tx, ty, tz)
and
+ * R
is a rotation transformation specified by the given quaternion.
+ *
+ * When transforming a vector by the resulting matrix the rotation transformation will be applied first and then the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaterniondc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param quat
+ * the quaternion representing a rotation
+ * @return this
+ */
+ public Matrix4x3d translationRotate(double tx, double ty, double tz, Quaterniondc quat) {
+ double dqx = quat.x() + quat.x(), dqy = quat.y() + quat.y(), dqz = quat.z() + quat.z();
+ double q00 = dqx * quat.x();
+ double q11 = dqy * quat.y();
+ double q22 = dqz * quat.z();
+ double q01 = dqx * quat.y();
+ double q02 = dqx * quat.z();
+ double q03 = dqx * quat.w();
+ double q12 = dqy * quat.z();
+ double q13 = dqy * quat.w();
+ double q23 = dqz * quat.w();
+ m00 = 1.0 - (q11 + q22);
+ m01 = q01 + q23;
+ m02 = q02 - q13;
+ m10 = q01 - q23;
+ m11 = 1.0 - (q22 + q00);
+ m12 = q12 + q03;
+ m20 = q02 + q13;
+ m21 = q12 - q03;
+ m22 = 1.0 - (q11 + q00);
+ m30 = tx;
+ m31 = ty;
+ m32 = tz;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation - and possibly scaling - transformation specified by the given quaternion and M
is the given matrix mat
.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).mul(mat)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaternionfc)
+ * @see #mul(Matrix4x3dc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param quat
+ * the quaternion representing a rotation
+ * @param mat
+ * the matrix to multiply with
+ * @return this
+ */
+ public Matrix4x3d translationRotateMul(double tx, double ty, double tz, Quaternionfc quat, Matrix4x3dc mat) {
+ return translationRotateMul(tx, ty, tz, quat.x(), quat.y(), quat.z(), quat.w(), mat);
+ }
+
+ /**
+ * Set this
matrix to T * R * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation - and possibly scaling - transformation specified by the quaternion (qx, qy, qz, qw)
and M
is the given matrix mat
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).mul(mat)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotate(Quaternionfc)
+ * @see #mul(Matrix4x3dc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param mat
+ * the matrix to multiply with
+ * @return this
+ */
+ public Matrix4x3d translationRotateMul(double tx, double ty, double tz, double qx, double qy, double qz, double qw, Matrix4x3dc mat) {
+ double w2 = qw * qw;
+ double x2 = qx * qx;
+ double y2 = qy * qy;
+ double z2 = qz * qz;
+ double zw = qz * qw;
+ double xy = qx * qy;
+ double xz = qx * qz;
+ double yw = qy * qw;
+ double yz = qy * qz;
+ double xw = qx * qw;
+ double nm00 = w2 + x2 - z2 - y2;
+ double nm01 = xy + zw + zw + xy;
+ double nm02 = xz - yw + xz - yw;
+ double nm10 = -zw + xy - zw + xy;
+ double nm11 = y2 - z2 + w2 - x2;
+ double nm12 = yz + yz + xw + xw;
+ double nm20 = yw + xz + xz + yw;
+ double nm21 = yz + yz - xw - xw;
+ double nm22 = z2 - y2 - x2 + w2;
+ m00 = nm00 * mat.m00() + nm10 * mat.m01() + nm20 * mat.m02();
+ m01 = nm01 * mat.m00() + nm11 * mat.m01() + nm21 * mat.m02();
+ m02 = nm02 * mat.m00() + nm12 * mat.m01() + nm22 * mat.m02();
+ m10 = nm00 * mat.m10() + nm10 * mat.m11() + nm20 * mat.m12();
+ m11 = nm01 * mat.m10() + nm11 * mat.m11() + nm21 * mat.m12();
+ m12 = nm02 * mat.m10() + nm12 * mat.m11() + nm22 * mat.m12();
+ m20 = nm00 * mat.m20() + nm10 * mat.m21() + nm20 * mat.m22();
+ m21 = nm01 * mat.m20() + nm11 * mat.m21() + nm21 * mat.m22();
+ m22 = nm02 * mat.m20() + nm12 * mat.m21() + nm22 * mat.m22();
+ m30 = nm00 * mat.m30() + nm10 * mat.m31() + nm20 * mat.m32() + tx;
+ m31 = nm01 * mat.m30() + nm11 * mat.m31() + nm21 * mat.m32() + ty;
+ m32 = nm02 * mat.m30() + nm12 * mat.m31() + nm22 * mat.m32() + tz;
+ this.properties = 0;
+ return this;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotate(Quaterniondc quat, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(quat);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(quat, dest);
+ return rotateGeneric(quat, dest);
+ }
+ private Matrix4x3d rotateGeneric(Quaterniondc quat, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = dxy - dzw;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotate(Quaternionfc quat, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(quat);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(quat, dest);
+ return rotateGeneric(quat, dest);
+ }
+ private Matrix4x3d rotateGeneric(Quaternionfc quat, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = xy + zw + zw + xy;
+ double rm02 = xz - yw + xz - yw;
+ double rm10 = -zw + xy - zw + xy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = yz + yz + xw + xw;
+ double rm20 = yw + xz + xz + yw;
+ double rm21 = yz + yz - xw - xw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4x3d rotate(Quaterniondc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3d rotate(Quaternionfc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateTranslation(Quaterniondc quat, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = dxy + dzw;
+ double rm02 = dxz - dyw;
+ double rm10 = dxy - dzw;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = dyz + dxw;
+ double rm20 = dyw + dxz;
+ double rm21 = dyz - dxw;
+ double rm22 = z2 - y2 - x2 + w2;
+ dest.m20 = rm20;
+ dest.m21 = rm21;
+ dest.m22 = rm22;
+ dest.m00 = rm00;
+ dest.m01 = rm01;
+ dest.m02 = rm02;
+ dest.m10 = rm10;
+ dest.m11 = rm11;
+ dest.m12 = rm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateTranslation(Quaternionfc quat, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w();
+ double x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y();
+ double z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w();
+ double xy = quat.x() * quat.y();
+ double xz = quat.x() * quat.z();
+ double yw = quat.y() * quat.w();
+ double yz = quat.y() * quat.z();
+ double xw = quat.x() * quat.w();
+ double rm00 = w2 + x2 - z2 - y2;
+ double rm01 = xy + zw + zw + xy;
+ double rm02 = xz - yw + xz - yw;
+ double rm10 = -zw + xy - zw + xy;
+ double rm11 = y2 - z2 + w2 - x2;
+ double rm12 = yz + yz + xw + xw;
+ double rm20 = yw + xz + xz + yw;
+ double rm21 = yz + yz - xw - xw;
+ double rm22 = z2 - y2 - x2 + w2;
+ double nm00 = rm00;
+ double nm01 = rm01;
+ double nm02 = rm02;
+ double nm10 = rm10;
+ double nm11 = rm11;
+ double nm12 = rm12;
+ dest.m20 = rm20;
+ dest.m21 = rm21;
+ dest.m22 = rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateLocal(Quaterniondc quat, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = dxy + dzw;
+ double lm02 = dxz - dyw;
+ double lm10 = dxy - dzw;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = dyz + dxw;
+ double lm20 = dyw + dxz;
+ double lm21 = dyz - dxw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation transformation of the given {@link Quaterniondc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaterniondc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaterniondc)
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4x3d rotateLocal(Quaterniondc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateLocal(Quaternionfc quat, Matrix4x3d dest) {
+ double w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ double y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ double zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ double xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ double yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ double lm00 = w2 + x2 - z2 - y2;
+ double lm01 = dxy + dzw;
+ double lm02 = dxz - dyw;
+ double lm10 = dxy - dzw;
+ double lm11 = y2 - z2 + w2 - x2;
+ double lm12 = dyz + dxw;
+ double lm20 = dyw + dxz;
+ double lm21 = dyz - dxw;
+ double lm22 = z2 - y2 - x2 + w2;
+ double nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ double nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ double nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ double nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ double nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ double nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ double nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ double nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ double nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ double nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ double nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ double nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3d rotateLocal(Quaternionfc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d rotate(AxisAngle4f axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotate(AxisAngle4f axisAngle, Matrix4x3d dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4d)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d rotate(AxisAngle4d axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4d)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(AxisAngle4d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotate(AxisAngle4d axisAngle, Matrix4x3d dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3dc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d rotate(double angle, Vector3dc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3dc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3dc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotate(double angle, Vector3dc axis, Matrix4x3d dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d rotate(double angle, Vector3fc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(double, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double)
+ * @see #rotation(double, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotate(double angle, Vector3fc axis, Matrix4x3d dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ public Vector4d getRow(int row, Vector4d dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ dest.x = m00;
+ dest.y = m10;
+ dest.z = m20;
+ dest.w = m30;
+ break;
+ case 1:
+ dest.x = m01;
+ dest.y = m11;
+ dest.z = m21;
+ dest.w = m31;
+ break;
+ case 2:
+ dest.x = m02;
+ dest.y = m12;
+ dest.z = m22;
+ dest.w = m32;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ public Matrix4x3d setRow(int row, Vector4dc src) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ this.m00 = src.x();
+ this.m10 = src.y();
+ this.m20 = src.z();
+ this.m30 = src.w();
+ break;
+ case 1:
+ this.m01 = src.x();
+ this.m11 = src.y();
+ this.m21 = src.z();
+ this.m31 = src.w();
+ break;
+ case 2:
+ this.m02 = src.x();
+ this.m12 = src.y();
+ this.m22 = src.z();
+ this.m32 = src.w();
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ properties = 0;
+ return this;
+ }
+
+ public Vector3d getColumn(int column, Vector3d dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ dest.x = m00;
+ dest.y = m01;
+ dest.z = m02;
+ break;
+ case 1:
+ dest.x = m10;
+ dest.y = m11;
+ dest.z = m12;
+ break;
+ case 2:
+ dest.x = m20;
+ dest.y = m21;
+ dest.z = m22;
+ break;
+ case 3:
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ public Matrix4x3d setColumn(int column, Vector3dc src) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ this.m00 = src.x();
+ this.m01 = src.y();
+ this.m02 = src.z();
+ break;
+ case 1:
+ this.m10 = src.x();
+ this.m11 = src.y();
+ this.m12 = src.z();
+ break;
+ case 2:
+ this.m20 = src.x();
+ this.m21 = src.y();
+ this.m22 = src.z();
+ break;
+ case 3:
+ this.m30 = src.x();
+ this.m31 = src.y();
+ this.m32 = src.z();
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into the left 3x3 submatrix of this
.
+ * All other values of this
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4x3dc)} to set a given Matrix4x3d to only the left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see #set3x3(Matrix4x3dc)
+ *
+ * @return this
+ */
+ public Matrix4x3d normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into the left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4x3dc)} to set a given Matrix4x3d to only the left 3x3 submatrix
+ * of a given matrix.
+ *
+ * @see #set3x3(Matrix4x3dc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d normal(Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix4x3d normalOrthonormal(Matrix4x3d dest) {
+ if (dest != this)
+ dest.set(this);
+ return dest._properties(PROPERTY_ORTHONORMAL);
+ }
+ private Matrix4x3d normalGeneric(Matrix4x3d dest) {
+ double m00m11 = m00 * m11;
+ double m01m10 = m01 * m10;
+ double m02m10 = m02 * m10;
+ double m00m12 = m00 * m12;
+ double m01m12 = m01 * m12;
+ double m02m11 = m02 * m11;
+ double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ double s = 1.0 / det;
+ /* Invert and transpose in one go */
+ double nm00 = (m11 * m22 - m21 * m12) * s;
+ double nm01 = (m20 * m12 - m10 * m22) * s;
+ double nm02 = (m10 * m21 - m20 * m11) * s;
+ double nm10 = (m21 * m02 - m01 * m22) * s;
+ double nm11 = (m00 * m22 - m20 * m02) * s;
+ double nm12 = (m20 * m01 - m00 * m21) * s;
+ double nm20 = (m01m12 - m02m11) * s;
+ double nm21 = (m02m10 - m00m12) * s;
+ double nm22 = (m00m11 - m01m10) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = 0.0;
+ dest.m31 = 0.0;
+ dest.m32 = 0.0;
+ dest.properties = properties & ~PROPERTY_TRANSLATION;
+ return dest;
+ }
+
+ public Matrix3d normal(Matrix3d dest) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix3d normalOrthonormal(Matrix3d dest) {
+ return dest.set(this);
+ }
+ private Matrix3d normalGeneric(Matrix3d dest) {
+ double m00m11 = m00 * m11;
+ double m01m10 = m01 * m10;
+ double m02m10 = m02 * m10;
+ double m00m12 = m00 * m12;
+ double m01m12 = m01 * m12;
+ double m02m11 = m02 * m11;
+ double det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ double s = 1.0 / det;
+ /* Invert and transpose in one go */
+ dest.m00((m11 * m22 - m21 * m12) * s);
+ dest.m01((m20 * m12 - m10 * m22) * s);
+ dest.m02((m10 * m21 - m20 * m11) * s);
+ dest.m10((m21 * m02 - m01 * m22) * s);
+ dest.m11((m00 * m22 - m20 * m02) * s);
+ dest.m12((m20 * m01 - m00 * m21) * s);
+ dest.m20((m01m12 - m02m11) * s);
+ dest.m21((m02m10 - m00m12) * s);
+ dest.m22((m00m11 - m01m10) * s);
+ return dest;
+ }
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal()} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @return this
+ */
+ public Matrix4x3d cofactor3x3() {
+ return cofactor3x3(this);
+ }
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3d cofactor3x3(Matrix3d dest) {
+ dest.m00 = m11 * m22 - m21 * m12;
+ dest.m01 = m20 * m12 - m10 * m22;
+ dest.m02 = m10 * m21 - m20 * m11;
+ dest.m10 = m21 * m02 - m01 * m22;
+ dest.m11 = m00 * m22 - m20 * m02;
+ dest.m12 = m20 * m01 - m00 * m21;
+ dest.m20 = m01 * m12 - m02 * m11;
+ dest.m21 = m02 * m10 - m00 * m12;
+ dest.m22 = m00 * m11 - m01 * m10;
+ return dest;
+ }
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4x3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d cofactor3x3(Matrix4x3d dest) {
+ double nm00 = m11 * m22 - m21 * m12;
+ double nm01 = m20 * m12 - m10 * m22;
+ double nm02 = m10 * m21 - m20 * m11;
+ double nm10 = m21 * m02 - m01 * m22;
+ double nm11 = m00 * m22 - m20 * m02;
+ double nm12 = m20 * m01 - m00 * m21;
+ double nm20 = m01 * m12 - m11 * m02;
+ double nm21 = m02 * m10 - m12 * m00;
+ double nm22 = m00 * m11 - m10 * m01;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = 0.0;
+ dest.m31 = 0.0;
+ dest.m32 = 0.0;
+ dest.properties = properties & ~PROPERTY_TRANSLATION;
+ return dest;
+ }
+
+ /**
+ * Normalize the left 3x3 submatrix of this matrix.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @return this
+ */
+ public Matrix4x3d normalize3x3() {
+ return normalize3x3(this);
+ }
+
+ public Matrix4x3d normalize3x3(Matrix4x3d dest) {
+ double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ dest.m00 = m00 * invXlen; dest.m01 = m01 * invXlen; dest.m02 = m02 * invXlen;
+ dest.m10 = m10 * invYlen; dest.m11 = m11 * invYlen; dest.m12 = m12 * invYlen;
+ dest.m20 = m20 * invZlen; dest.m21 = m21 * invZlen; dest.m22 = m22 * invZlen;
+ return dest;
+ }
+
+ public Matrix3d normalize3x3(Matrix3d dest) {
+ double invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ double invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ double invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ dest.m00(m00 * invXlen); dest.m01(m01 * invXlen); dest.m02(m02 * invXlen);
+ dest.m10(m10 * invYlen); dest.m11(m11 * invYlen); dest.m12(m12 * invYlen);
+ dest.m20(m20 * invZlen); dest.m21(m21 * invZlen); dest.m22(m22 * invZlen);
+ return dest;
+ }
+
+ public Matrix4x3d reflect(double a, double b, double c, double d, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.reflection(a, b, c, d);
+
+ double da = a + a, db = b + b, dc = c + c, dd = d + d;
+ double rm00 = 1.0 - da * a;
+ double rm01 = -da * b;
+ double rm02 = -da * c;
+ double rm10 = -db * a;
+ double rm11 = 1.0 - db * b;
+ double rm12 = -db * c;
+ double rm20 = -dc * a;
+ double rm21 = -dc * b;
+ double rm22 = 1.0 - dc * c;
+ double rm30 = -dd * a;
+ double rm31 = -dd * b;
+ double rm32 = -dd * c;
+
+ // matrix multiplication
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3d reflect(double a, double b, double c, double d) {
+ return reflect(a, b, c, d, this);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz) {
+ return reflect(nx, ny, nz, px, py, pz, this);
+ }
+
+ public Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz, Matrix4x3d dest) {
+ double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ double nnx = nx * invLength;
+ double nny = ny * invLength;
+ double nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3d reflect(Vector3dc normal, Vector3dc point) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation relative to an implied normal vector of (0, 0, 1)
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3d reflect(Quaterniondc orientation, Vector3dc point) {
+ return reflect(orientation, point, this);
+ }
+
+ public Matrix4x3d reflect(Quaterniondc orientation, Vector3dc point, Matrix4x3d dest) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ double normalX = orientation.x() * num3 + orientation.w() * num2;
+ double normalY = orientation.y() * num3 - orientation.w() * num1;
+ double normalZ = 1.0 - (orientation.x() * num1 + orientation.y() * num2);
+ return reflect(normalX, normalY, normalZ, point.x(), point.y(), point.z(), dest);
+ }
+
+ public Matrix4x3d reflect(Vector3dc normal, Vector3dc point, Matrix4x3d dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z(), dest);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3d reflection(double a, double b, double c, double d) {
+ double da = a + a, db = b + b, dc = c + c, dd = d + d;
+ m00 = 1.0 - da * a;
+ m01 = -da * b;
+ m02 = -da * c;
+ m10 = -db * a;
+ m11 = 1.0 - db * b;
+ m12 = -db * c;
+ m20 = -dc * a;
+ m21 = -dc * b;
+ m22 = 1.0 - dc * c;
+ m30 = -dd * a;
+ m31 = -dd * b;
+ m32 = -dd * c;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4x3d reflection(double nx, double ny, double nz, double px, double py, double pz) {
+ double invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ double nnx = nx * invLength;
+ double nny = ny * invLength;
+ double nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3d reflection(Vector3dc normal, Vector3dc point) {
+ return reflection(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3d reflection(Quaterniondc orientation, Vector3dc point) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ double normalX = orientation.x() * num3 + orientation.w() * num2;
+ double normalY = orientation.y() * num3 - orientation.w() * num1;
+ double normalZ = 1.0 - (orientation.x() * num1 + orientation.y() * num2);
+ return reflection(normalX, normalY, normalZ, point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
+ double rm30 = (left + right) / (left - right);
+ double rm31 = (top + bottom) / (bottom - top);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4x3d dest) {
+ return ortho(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ return ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(double, double, double, double, double, double) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return ortho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
+ double rm30 = (left + right) / (left - right);
+ double rm31 = (top + bottom) / (bottom - top);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4x3d dest) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(double, double, double, double, double, double, boolean) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ m00 = 2.0 / (right - left);
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / (top - bottom);
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
+ m30 = (right + left) / (left - right);
+ m31 = (top + bottom) / (bottom - top);
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(double, double, double, double, double, double) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d setOrtho(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return setOrtho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(double, double, double, double, double, double, boolean) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne) {
+ m00 = 2.0 / (right - left);
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / (top - bottom);
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
+ m30 = (right + left) / (left - right);
+ m31 = (top + bottom) / (bottom - top);
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(double, double, double, double, double, double) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d setOrthoLH(double left, double right, double bottom, double top, double zNear, double zFar) {
+ return setOrthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, boolean, Matrix4x3d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / width;
+ double rm11 = 2.0 / height;
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m20 * rm32 + m30;
+ dest.m31 = m21 * rm32 + m31;
+ dest.m32 = m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, Matrix4x3d dest) {
+ return orthoSymmetric(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, boolean) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ return orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(double, double, double, double) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar) {
+ return orthoSymmetric(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, boolean, Matrix4x3d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / width;
+ double rm11 = 2.0 / height;
+ double rm22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
+ double rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m20 * rm32 + m30;
+ dest.m31 = m21 * rm32 + m31;
+ dest.m32 = m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, Matrix4x3d dest) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, boolean) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ return orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(double, double, double, double) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(double, double, double, double, boolean) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d setOrthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ m00 = 2.0 / width;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / height;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = (zZeroToOne ? 1.0 : 2.0) / (zNear - zFar);
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(double, double, double, double) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d setOrthoSymmetric(double width, double height, double zNear, double zFar) {
+ return setOrthoSymmetric(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(double, double, double, double, boolean) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(double, double, double, double, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3d setOrthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne) {
+ m00 = 2.0 / width;
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / height;
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = (zZeroToOne ? 1.0 : 2.0) / (zFar - zNear);
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrthoLH(double, double, double, double, double, double) setOrthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(double, double, double, double) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(double, double, double, double)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3d setOrthoSymmetricLH(double width, double height, double zNear, double zFar) {
+ return setOrthoSymmetricLH(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(double, double, double, double) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double, Matrix4x3d)
+ * @see #setOrtho2D(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d ortho2D(double left, double right, double bottom, double top, Matrix4x3d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm30 = -(right + left) / (right - left);
+ double rm31 = -(top + bottom) / (top - bottom);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = -m20;
+ dest.m21 = -m21;
+ dest.m22 = -m22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(double, double, double, double) setOrtho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double)
+ * @see #setOrtho2D(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3d ortho2D(double left, double right, double bottom, double top) {
+ return ortho2D(left, right, bottom, top, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(double, double, double, double) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double, Matrix4x3d)
+ * @see #setOrtho2DLH(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d ortho2DLH(double left, double right, double bottom, double top, Matrix4x3d dest) {
+ // calculate right matrix elements
+ double rm00 = 2.0 / (right - left);
+ double rm11 = 2.0 / (top - bottom);
+ double rm30 = -(right + left) / (right - left);
+ double rm31 = -(top + bottom) / (top - bottom);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(double, double, double, double) setOrtho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double)
+ * @see #setOrtho2DLH(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3d ortho2DLH(double left, double right, double bottom, double top) {
+ return ortho2DLH(left, right, bottom, top, this);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrtho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2D(double, double, double, double) ortho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(double, double, double, double, double, double)
+ * @see #ortho2D(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3d setOrtho2D(double left, double right, double bottom, double top) {
+ m00 = 2.0 / (right - left);
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / (top - bottom);
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = -1.0;
+ m30 = -(right + left) / (right - left);
+ m31 = -(top + bottom) / (top - bottom);
+ m32 = 0.0;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(double, double, double, double, double, double) setOrthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2DLH(double, double, double, double) ortho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(double, double, double, double, double, double)
+ * @see #ortho2DLH(double, double, double, double)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3d setOrtho2DLH(double left, double right, double bottom, double top) {
+ m00 = 2.0 / (right - left);
+ m01 = 0.0;
+ m02 = 0.0;
+ m10 = 0.0;
+ m11 = 2.0 / (top - bottom);
+ m12 = 0.0;
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ m30 = -(right + left) / (right - left);
+ m31 = -(top + bottom) / (top - bottom);
+ m32 = 0.0;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3dc, Vector3dc, Vector3dc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3dc, Vector3dc) setLookAlong()}.
+ *
+ * @see #lookAlong(double, double, double, double, double, double)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3d lookAlong(Vector3dc dir, Vector3dc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3dc, Vector3dc, Vector3dc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3dc, Vector3dc) setLookAlong()}.
+ *
+ * @see #lookAlong(double, double, double, double, double, double)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d lookAlong(Vector3dc dir, Vector3dc up, Matrix4x3d dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d lookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return setLookAlong(dirX, dirY, dirZ, upX, upY, upZ);
+
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+
+ // perform optimized matrix multiplication
+ // introduce temporaries for dependent results
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(double, double, double, double, double, double) setLookAlong()}
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d lookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc) setLookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(Vector3dc, Vector3dc)}.
+ *
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ * @see #lookAlong(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3d setLookAlong(Vector3dc dir, Vector3dc up) {
+ return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(double, double, double, double, double, double, double, double, double)
+ * setLookAt()} with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(double, double, double, double, double, double) lookAlong()}
+ *
+ * @see #setLookAlong(double, double, double, double, double, double)
+ * @see #lookAlong(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d setLookAlong(double dirX, double dirY, double dirZ,
+ double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+ m30 = 0.0;
+ m31 = 0.0;
+ m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns
+ * -z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(Vector3dc, Vector3dc, Vector3dc) lookAt()}.
+ *
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3d setLookAt(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return setLookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(double, double, double, double, double, double, double, double, double) lookAt}.
+ *
+ * @see #setLookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d setLookAt(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+ m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ properties = PROPERTY_ORTHONORMAL;
+
+ return this;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d lookAt(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4x3d dest) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double)
+ * @see #setLookAlong(Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3d lookAt(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
+ *
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4x3d lookAtGeneric(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4x3d dest) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+ double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ // introduce temporaries for dependent results
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(double, double, double, double, double, double, double, double, double) setLookAt()}.
+ *
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAt(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ return lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns
+ * +z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(Vector3dc, Vector3dc, Vector3dc) lookAt()}.
+ *
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3d setLookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return setLookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(double, double, double, double, double, double, double, double, double) lookAtLH}.
+ *
+ * @see #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d setLookAtLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+ m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ properties = PROPERTY_ORTHONORMAL;
+
+ return this;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d lookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4x3d dest) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3d lookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4x3d dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4x3d lookAtLHGeneric(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ, Matrix4x3d dest) {
+ // Compute direction from position to lookAt
+ double dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirY * leftZ - dirZ * leftY;
+ double upnY = dirZ * leftX - dirX * leftZ;
+ double upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ double rm00 = leftX;
+ double rm01 = upnX;
+ double rm02 = dirX;
+ double rm10 = leftY;
+ double rm11 = upnY;
+ double rm12 = dirY;
+ double rm20 = leftZ;
+ double rm21 = upnZ;
+ double rm22 = dirZ;
+ double rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ double rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ double rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ // introduce temporaries for dependent results
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(double, double, double, double, double, double, double, double, double) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc)
+ * @see #setLookAtLH(double, double, double, double, double, double, double, double, double)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ,
+ double centerX, double centerY, double centerZ,
+ double upX, double upY, double upZ) {
+ return lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ public Vector4d frustumPlane(int which, Vector4d dest) {
+ switch (which) {
+ case PLANE_NX:
+ dest.set(m00, m10, m20, 1.0 + m30).normalize();
+ break;
+ case PLANE_PX:
+ dest.set(-m00, -m10, -m20, 1.0 - m30).normalize();
+ break;
+ case PLANE_NY:
+ dest.set(m01, m11, m21, 1.0 + m31).normalize();
+ break;
+ case PLANE_PY:
+ dest.set(-m01, -m11, -m21, 1.0 - m31).normalize();
+ break;
+ case PLANE_NZ:
+ dest.set(m02, m12, m22, 1.0 + m32).normalize();
+ break;
+ case PLANE_PZ:
+ dest.set(-m02, -m12, -m22, 1.0 - m32).normalize();
+ break;
+ default:
+ throw new IllegalArgumentException("which"); //$NON-NLS-1$
+ }
+ return dest;
+ }
+
+ public Vector3d positiveZ(Vector3d dir) {
+ dir.x = m10 * m21 - m11 * m20;
+ dir.y = m20 * m01 - m21 * m00;
+ dir.z = m00 * m11 - m01 * m10;
+ return dir.normalize(dir);
+ }
+
+ public Vector3d normalizedPositiveZ(Vector3d dir) {
+ dir.x = m02;
+ dir.y = m12;
+ dir.z = m22;
+ return dir;
+ }
+
+ public Vector3d positiveX(Vector3d dir) {
+ dir.x = m11 * m22 - m12 * m21;
+ dir.y = m02 * m21 - m01 * m22;
+ dir.z = m01 * m12 - m02 * m11;
+ return dir.normalize(dir);
+ }
+
+ public Vector3d normalizedPositiveX(Vector3d dir) {
+ dir.x = m00;
+ dir.y = m10;
+ dir.z = m20;
+ return dir;
+ }
+
+ public Vector3d positiveY(Vector3d dir) {
+ dir.x = m12 * m20 - m10 * m22;
+ dir.y = m00 * m22 - m02 * m20;
+ dir.z = m02 * m10 - m00 * m12;
+ return dir.normalize(dir);
+ }
+
+ public Vector3d normalizedPositiveY(Vector3d dir) {
+ dir.x = m01;
+ dir.y = m11;
+ dir.z = m21;
+ return dir;
+ }
+
+ public Vector3d origin(Vector3d origin) {
+ double a = m00 * m11 - m01 * m10;
+ double b = m00 * m12 - m02 * m10;
+ double d = m01 * m12 - m02 * m11;
+ double g = m20 * m31 - m21 * m30;
+ double h = m20 * m32 - m22 * m30;
+ double j = m21 * m32 - m22 * m31;
+ origin.x = -m10 * j + m11 * h - m12 * g;
+ origin.y = m00 * j - m01 * h + m02 * g;
+ origin.z = -m30 * d + m31 * b - m32 * a;
+ return origin;
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3d shadow(Vector4dc light, double a, double b, double c, double d) {
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, this);
+ }
+
+ public Matrix4x3d shadow(Vector4dc light, double a, double b, double c, double d, Matrix4x3d dest) {
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d) {
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this);
+ }
+
+ public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, Matrix4x3d dest) {
+ // normalize plane
+ double invPlaneLen = Math.invsqrt(a*a + b*b + c*c);
+ double an = a * invPlaneLen;
+ double bn = b * invPlaneLen;
+ double cn = c * invPlaneLen;
+ double dn = d * invPlaneLen;
+
+ double dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW;
+
+ // compute right matrix elements
+ double rm00 = dot - an * lightX;
+ double rm01 = -an * lightY;
+ double rm02 = -an * lightZ;
+ double rm03 = -an * lightW;
+ double rm10 = -bn * lightX;
+ double rm11 = dot - bn * lightY;
+ double rm12 = -bn * lightZ;
+ double rm13 = -bn * lightW;
+ double rm20 = -cn * lightX;
+ double rm21 = -cn * lightY;
+ double rm22 = dot - cn * lightZ;
+ double rm23 = -cn * lightW;
+ double rm30 = -dn * lightX;
+ double rm31 = -dn * lightY;
+ double rm32 = -dn * lightZ;
+ double rm33 = dot - dn * lightW;
+
+ // matrix multiplication
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13;
+ double nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23;
+ double nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23;
+ double nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23;
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ public Matrix4x3d shadow(Vector4dc light, Matrix4x3dc planeTransform, Matrix4x3d dest) {
+ // compute plane equation by transforming (y = 0)
+ double a = planeTransform.m10();
+ double b = planeTransform.m11();
+ double c = planeTransform.m12();
+ double d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4x3d shadow(Vector4dc light, Matrix4x3dc planeTransform) {
+ return shadow(light, planeTransform, this);
+ }
+
+ public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3dc planeTransform, Matrix4x3d dest) {
+ // compute plane equation by transforming (y = 0)
+ double a = planeTransform.m10();
+ double b = planeTransform.m11();
+ double c = planeTransform.m12();
+ double d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3dc planeTransform) {
+ return shadow(lightX, lightY, lightZ, lightW, planeTransform, this);
+ }
+
+ /**
+ * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
while constraining a cylindrical rotation around the given up
vector.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the rotation axis (must be {@link Vector3d#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3d billboardCylindrical(Vector3dc objPos, Vector3dc targetPos, Vector3dc up) {
+ double dirX = targetPos.x() - objPos.x();
+ double dirY = targetPos.y() - objPos.y();
+ double dirZ = targetPos.z() - objPos.z();
+ // left = up x dir
+ double leftX = up.y() * dirZ - up.z() * dirY;
+ double leftY = up.z() * dirX - up.x() * dirZ;
+ double leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // recompute dir by constraining rotation around 'up'
+ // dir = left x up
+ dirX = leftY * up.z() - leftZ * up.y();
+ dirY = leftZ * up.x() - leftX * up.z();
+ dirZ = leftX * up.y() - leftY * up.x();
+ // normalize dir
+ double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // set matrix elements
+ m00 = leftX;
+ m01 = leftY;
+ m02 = leftZ;
+ m10 = up.x();
+ m11 = up.y();
+ m12 = up.z();
+ m20 = dirX;
+ m21 = dirY;
+ m22 = dirZ;
+ m30 = objPos.x();
+ m31 = objPos.y();
+ m32 = objPos.z();
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * If preserving an up vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained
+ * using {@link #billboardSpherical(Vector3dc, Vector3dc)}.
+ *
+ * @see #billboardSpherical(Vector3dc, Vector3dc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the up axis used to orient the object
+ * @return this
+ */
+ public Matrix4x3d billboardSpherical(Vector3dc objPos, Vector3dc targetPos, Vector3dc up) {
+ double dirX = targetPos.x() - objPos.x();
+ double dirY = targetPos.y() - objPos.y();
+ double dirZ = targetPos.z() - objPos.z();
+ // normalize dir
+ double invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // left = up x dir
+ double leftX = up.y() * dirZ - up.z() * dirY;
+ double leftY = up.z() * dirX - up.x() * dirZ;
+ double leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ double invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // up = dir x left
+ double upX = dirY * leftZ - dirZ * leftY;
+ double upY = dirZ * leftX - dirX * leftZ;
+ double upZ = dirX * leftY - dirY * leftX;
+ // set matrix elements
+ m00 = leftX;
+ m01 = leftY;
+ m02 = leftZ;
+ m10 = upX;
+ m11 = upY;
+ m12 = upZ;
+ m20 = dirX;
+ m21 = dirY;
+ m22 = dirZ;
+ m30 = objPos.x();
+ m31 = objPos.y();
+ m32 = objPos.z();
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
using a shortest arc rotation by not preserving any up vector of the object.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * In order to specify an up vector which needs to be maintained when rotating the +Z axis of the object,
+ * use {@link #billboardSpherical(Vector3dc, Vector3dc, Vector3dc)}.
+ *
+ * @see #billboardSpherical(Vector3dc, Vector3dc, Vector3dc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @return this
+ */
+ public Matrix4x3d billboardSpherical(Vector3dc objPos, Vector3dc targetPos) {
+ double toDirX = targetPos.x() - objPos.x();
+ double toDirY = targetPos.y() - objPos.y();
+ double toDirZ = targetPos.z() - objPos.z();
+ double x = -toDirY;
+ double y = toDirX;
+ double w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ;
+ double invNorm = Math.invsqrt(x * x + y * y + w * w);
+ x *= invNorm;
+ y *= invNorm;
+ w *= invNorm;
+ double q00 = (x + x) * x;
+ double q11 = (y + y) * y;
+ double q01 = (x + x) * y;
+ double q03 = (x + x) * w;
+ double q13 = (y + y) * w;
+ m00 = 1.0 - q11;
+ m01 = q01;
+ m02 = -q13;
+ m10 = q01;
+ m11 = 1.0 - q00;
+ m12 = q03;
+ m20 = q13;
+ m21 = -q03;
+ m22 = 1.0 - q11 - q00;
+ m30 = objPos.x();
+ m31 = objPos.y();
+ m32 = objPos.z();
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(m00);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m01);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m02);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m10);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m11);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m12);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m20);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m21);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m22);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m30);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m31);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(m32);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof Matrix4x3d))
+ return false;
+ Matrix4x3d other = (Matrix4x3d) obj;
+ if (Double.doubleToLongBits(m00) != Double.doubleToLongBits(other.m00))
+ return false;
+ if (Double.doubleToLongBits(m01) != Double.doubleToLongBits(other.m01))
+ return false;
+ if (Double.doubleToLongBits(m02) != Double.doubleToLongBits(other.m02))
+ return false;
+ if (Double.doubleToLongBits(m10) != Double.doubleToLongBits(other.m10))
+ return false;
+ if (Double.doubleToLongBits(m11) != Double.doubleToLongBits(other.m11))
+ return false;
+ if (Double.doubleToLongBits(m12) != Double.doubleToLongBits(other.m12))
+ return false;
+ if (Double.doubleToLongBits(m20) != Double.doubleToLongBits(other.m20))
+ return false;
+ if (Double.doubleToLongBits(m21) != Double.doubleToLongBits(other.m21))
+ return false;
+ if (Double.doubleToLongBits(m22) != Double.doubleToLongBits(other.m22))
+ return false;
+ if (Double.doubleToLongBits(m30) != Double.doubleToLongBits(other.m30))
+ return false;
+ if (Double.doubleToLongBits(m31) != Double.doubleToLongBits(other.m31))
+ return false;
+ if (Double.doubleToLongBits(m32) != Double.doubleToLongBits(other.m32))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix4x3dc m, double delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix4x3d))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m02, m.m02(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m12, m.m12(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ if (!Runtime.equals(m22, m.m22(), delta))
+ return false;
+ if (!Runtime.equals(m30, m.m30(), delta))
+ return false;
+ if (!Runtime.equals(m31, m.m31(), delta))
+ return false;
+ if (!Runtime.equals(m32, m.m32(), delta))
+ return false;
+ return true;
+ }
+
+ public Matrix4x3d pick(double x, double y, double width, double height, int[] viewport, Matrix4x3d dest) {
+ double sx = viewport[2] / width;
+ double sy = viewport[3] / height;
+ double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
+ double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
+ dest.m30 = m00 * tx + m10 * ty + m30;
+ dest.m31 = m01 * tx + m11 * ty + m31;
+ dest.m32 = m02 * tx + m12 * ty + m32;
+ dest.m00 = m00 * sx;
+ dest.m01 = m01 * sx;
+ dest.m02 = m02 * sx;
+ dest.m10 = m10 * sy;
+ dest.m11 = m11 * sy;
+ dest.m12 = m12 * sy;
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @return this
+ */
+ public Matrix4x3d pick(double x, double y, double width, double height, int[] viewport) {
+ return pick(x, y, width, height, viewport, this);
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix4x3d swap(Matrix4x3d other) {
+ double tmp;
+ tmp = m00; m00 = other.m00; other.m00 = tmp;
+ tmp = m01; m01 = other.m01; other.m01 = tmp;
+ tmp = m02; m02 = other.m02; other.m02 = tmp;
+ tmp = m10; m10 = other.m10; other.m10 = tmp;
+ tmp = m11; m11 = other.m11; other.m11 = tmp;
+ tmp = m12; m12 = other.m12; other.m12 = tmp;
+ tmp = m20; m20 = other.m20; other.m20 = tmp;
+ tmp = m21; m21 = other.m21; other.m21 = tmp;
+ tmp = m22; m22 = other.m22; other.m22 = tmp;
+ tmp = m30; m30 = other.m30; other.m30 = tmp;
+ tmp = m31; m31 = other.m31; other.m31 = tmp;
+ tmp = m32; m32 = other.m32; other.m32 = tmp;
+ int props = properties;
+ this.properties = other.properties;
+ other.properties = props;
+ return this;
+ }
+
+ public Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, Matrix4x3d dest) {
+ double m30 = m20 * -radius + this.m30;
+ double m31 = m21 * -radius + this.m31;
+ double m32 = m22 * -radius + this.m32;
+ double sin = Math.sin(angleX);
+ double cos = Math.cosFromSin(sin, angleX);
+ double nm10 = m10 * cos + m20 * sin;
+ double nm11 = m11 * cos + m21 * sin;
+ double nm12 = m12 * cos + m22 * sin;
+ double m20 = this.m20 * cos - m10 * sin;
+ double m21 = this.m21 * cos - m11 * sin;
+ double m22 = this.m22 * cos - m12 * sin;
+ sin = Math.sin(angleY);
+ cos = Math.cosFromSin(sin, angleY);
+ double nm00 = m00 * cos - m20 * sin;
+ double nm01 = m01 * cos - m21 * sin;
+ double nm02 = m02 * cos - m22 * sin;
+ double nm20 = m00 * sin + m20 * cos;
+ double nm21 = m01 * sin + m21 * cos;
+ double nm22 = m02 * sin + m22 * cos;
+ dest.m30 = -nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30;
+ dest.m31 = -nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31;
+ dest.m32 = -nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ public Matrix4x3d arcball(double radius, Vector3dc center, double angleX, double angleY, Matrix4x3d dest) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, dest);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY) {
+ return arcball(radius, centerX, centerY, centerZ, angleX, angleY, this);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4x3d arcball(double radius, Vector3dc center, double angleX, double angleY) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, this);
+ }
+
+ public Matrix4x3d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector3d outMin, Vector3d outMax) {
+ double xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX;
+ double xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX;
+ double yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY;
+ double ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY;
+ double zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ;
+ double zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ;
+ double xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz;
+ double xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz;
+ if (xax < xbx) {
+ xminx = xax;
+ xmaxx = xbx;
+ } else {
+ xminx = xbx;
+ xmaxx = xax;
+ }
+ if (xay < xby) {
+ xminy = xay;
+ xmaxy = xby;
+ } else {
+ xminy = xby;
+ xmaxy = xay;
+ }
+ if (xaz < xbz) {
+ xminz = xaz;
+ xmaxz = xbz;
+ } else {
+ xminz = xbz;
+ xmaxz = xaz;
+ }
+ if (yax < ybx) {
+ yminx = yax;
+ ymaxx = ybx;
+ } else {
+ yminx = ybx;
+ ymaxx = yax;
+ }
+ if (yay < yby) {
+ yminy = yay;
+ ymaxy = yby;
+ } else {
+ yminy = yby;
+ ymaxy = yay;
+ }
+ if (yaz < ybz) {
+ yminz = yaz;
+ ymaxz = ybz;
+ } else {
+ yminz = ybz;
+ ymaxz = yaz;
+ }
+ if (zax < zbx) {
+ zminx = zax;
+ zmaxx = zbx;
+ } else {
+ zminx = zbx;
+ zmaxx = zax;
+ }
+ if (zay < zby) {
+ zminy = zay;
+ zmaxy = zby;
+ } else {
+ zminy = zby;
+ zmaxy = zay;
+ }
+ if (zaz < zbz) {
+ zminz = zaz;
+ zmaxz = zbz;
+ } else {
+ zminz = zbz;
+ zmaxz = zaz;
+ }
+ outMin.x = xminx + yminx + zminx + m30;
+ outMin.y = xminy + yminy + zminy + m31;
+ outMin.z = xminz + yminz + zminz + m32;
+ outMax.x = xmaxx + ymaxx + zmaxx + m30;
+ outMax.y = xmaxy + ymaxy + zmaxy + m31;
+ outMax.z = xmaxz + ymaxz + zmaxz + m32;
+ return this;
+ }
+
+ public Matrix4x3d transformAab(Vector3dc min, Vector3dc max, Vector3d outMin, Vector3d outMax) {
+ return transformAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), outMin, outMax);
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix4x3d lerp(Matrix4x3dc other, double t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix4x3d lerp(Matrix4x3dc other, double t, Matrix4x3d dest) {
+ dest.m00 = Math.fma(other.m00() - m00, t, m00);
+ dest.m01 = Math.fma(other.m01() - m01, t, m01);
+ dest.m02 = Math.fma(other.m02() - m02, t, m02);
+ dest.m10 = Math.fma(other.m10() - m10, t, m10);
+ dest.m11 = Math.fma(other.m11() - m11, t, m11);
+ dest.m12 = Math.fma(other.m12() - m12, t, m12);
+ dest.m20 = Math.fma(other.m20() - m20, t, m20);
+ dest.m21 = Math.fma(other.m21() - m21, t, m21);
+ dest.m22 = Math.fma(other.m22() - m22, t, m22);
+ dest.m30 = Math.fma(other.m30() - m30, t, m30);
+ dest.m31 = Math.fma(other.m31() - m31, t, m31);
+ dest.m32 = Math.fma(other.m32() - m32, t, m32);
+ dest.properties = properties & other.properties();
+ return dest;
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3dc, Vector3dc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(double, double, double, double, double, double, Matrix4x3d)
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateTowards(Vector3dc dir, Vector3dc up, Matrix4x3d dest) {
+ return rotateTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3dc, Vector3dc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert())
+ *
+ * @see #rotateTowards(double, double, double, double, double, double)
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ *
+ * @param dir
+ * the direction to orient towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3d rotateTowards(Vector3dc dir, Vector3dc up) {
+ return rotateTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert())
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(double, double, double, double, double, double) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4x3d dest) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ double rm00 = leftX;
+ double rm01 = leftY;
+ double rm02 = leftZ;
+ double rm10 = upnX;
+ double rm11 = upnY;
+ double rm12 = upnZ;
+ double rm20 = ndirX;
+ double rm21 = ndirY;
+ double rm22 = ndirZ;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ double nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ double nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ double nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ double nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ double nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ double nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with dir
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert()
+ *
+ * @see #rotationTowards(Vector3dc, Vector3dc)
+ * @see #rotateTowards(double, double, double, double, double, double)
+ *
+ * @param dir
+ * the direction to orient the local -z axis towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3d rotationTowards(Vector3dc dir, Vector3dc up) {
+ return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with (dirX, dirY, dirZ)
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(double, double, double, double, double, double) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert()
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ * @see #rotationTowards(double, double, double, double, double, double)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d rotationTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ this.m30 = 0.0;
+ this.m31 = 0.0;
+ this.m32 = 0.0;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given pos
and aligns the local -z
+ * axis with dir
.
+ *
+ * This method is equivalent to calling: translation(pos).rotateTowards(dir, up)
+ *
+ * @see #translation(Vector3dc)
+ * @see #rotateTowards(Vector3dc, Vector3dc)
+ *
+ * @param pos
+ * the position to translate to
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3d translationRotateTowards(Vector3dc pos, Vector3dc dir, Vector3dc up) {
+ return translationRotateTowards(pos.x(), pos.y(), pos.z(), dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given (posX, posY, posZ)
and aligns the local -z
+ * axis with (dirX, dirY, dirZ)
.
+ *
+ * This method is equivalent to calling: translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)
+ *
+ * @see #translation(double, double, double)
+ * @see #rotateTowards(double, double, double, double, double, double)
+ *
+ * @param posX
+ * the x-coordinate of the position to translate to
+ * @param posY
+ * the y-coordinate of the position to translate to
+ * @param posZ
+ * the z-coordinate of the position to translate to
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3d translationRotateTowards(double posX, double posY, double posZ, double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double ndirX = dirX * invDirLength;
+ double ndirY = dirY * invDirLength;
+ double ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ double leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = ndirY * leftZ - ndirZ * leftY;
+ double upnY = ndirZ * leftX - ndirX * leftZ;
+ double upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ this.m30 = posX;
+ this.m31 = posY;
+ this.m32 = posZ;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ public Vector3d getEulerAnglesZYX(Vector3d dest) {
+ dest.x = Math.atan2(m12, m22);
+ dest.y = Math.atan2(-m02, Math.sqrt(1.0 - m02 * m02));
+ dest.z = Math.atan2(m01, m00);
+ return dest;
+ }
+
+ public Vector3d getEulerAnglesXYZ(Vector3d dest) {
+ dest.x = Math.atan2(-m21, m22);
+ dest.y = Math.atan2(m20, Math.sqrt(1.0 - m20 * m20));
+ dest.z = Math.atan2(-m10, m00);
+ return dest;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @return this
+ */
+ public Matrix4x3d obliqueZ(double a, double b) {
+ this.m20 = m00 * a + m10 * b + m20;
+ this.m21 = m01 * a + m11 * b + m21;
+ this.m22 = m02 * a + m12 * b + m22;
+ this.properties = 0;
+ return this;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3d obliqueZ(double a, double b, Matrix4x3d dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m00 * a + m10 * b + m20;
+ dest.m21 = m01 * a + m11 * b + m21;
+ dest.m22 = m02 * a + m12 * b + m22;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapXZY() {
+ return mapXZY(this);
+ }
+ public Matrix4x3d mapXZY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapXZnY() {
+ return mapXZnY(this);
+ }
+ public Matrix4x3d mapXZnY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapXnYnZ() {
+ return mapXnYnZ(this);
+ }
+ public Matrix4x3d mapXnYnZ(Matrix4x3d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapXnZY() {
+ return mapXnZY(this);
+ }
+ public Matrix4x3d mapXnZY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapXnZnY() {
+ return mapXnZnY(this);
+ }
+ public Matrix4x3d mapXnZnY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYXZ() {
+ return mapYXZ(this);
+ }
+ public Matrix4x3d mapYXZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYXnZ() {
+ return mapYXnZ(this);
+ }
+ public Matrix4x3d mapYXnZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYZX() {
+ return mapYZX(this);
+ }
+ public Matrix4x3d mapYZX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYZnX() {
+ return mapYZnX(this);
+ }
+ public Matrix4x3d mapYZnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYnXZ() {
+ return mapYnXZ(this);
+ }
+ public Matrix4x3d mapYnXZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYnXnZ() {
+ return mapYnXnZ(this);
+ }
+ public Matrix4x3d mapYnXnZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYnZX() {
+ return mapYnZX(this);
+ }
+ public Matrix4x3d mapYnZX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapYnZnX() {
+ return mapYnZnX(this);
+ }
+ public Matrix4x3d mapYnZnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZXY() {
+ return mapZXY(this);
+ }
+ public Matrix4x3d mapZXY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZXnY() {
+ return mapZXnY(this);
+ }
+ public Matrix4x3d mapZXnY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZYX() {
+ return mapZYX(this);
+ }
+ public Matrix4x3d mapZYX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZYnX() {
+ return mapZYnX(this);
+ }
+ public Matrix4x3d mapZYnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZnXY() {
+ return mapZnXY(this);
+ }
+ public Matrix4x3d mapZnXY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZnXnY() {
+ return mapZnXnY(this);
+ }
+ public Matrix4x3d mapZnXnY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZnYX() {
+ return mapZnYX(this);
+ }
+ public Matrix4x3d mapZnYX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapZnYnX() {
+ return mapZnYnX(this);
+ }
+ public Matrix4x3d mapZnYnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXYnZ() {
+ return mapnXYnZ(this);
+ }
+ public Matrix4x3d mapnXYnZ(Matrix4x3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXZY() {
+ return mapnXZY(this);
+ }
+ public Matrix4x3d mapnXZY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXZnY() {
+ return mapnXZnY(this);
+ }
+ public Matrix4x3d mapnXZnY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXnYZ() {
+ return mapnXnYZ(this);
+ }
+ public Matrix4x3d mapnXnYZ(Matrix4x3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXnYnZ() {
+ return mapnXnYnZ(this);
+ }
+ public Matrix4x3d mapnXnYnZ(Matrix4x3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXnZY() {
+ return mapnXnZY(this);
+ }
+ public Matrix4x3d mapnXnZY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnXnZnY() {
+ return mapnXnZnY(this);
+ }
+ public Matrix4x3d mapnXnZnY(Matrix4x3d dest) {
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYXZ() {
+ return mapnYXZ(this);
+ }
+ public Matrix4x3d mapnYXZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYXnZ() {
+ return mapnYXnZ(this);
+ }
+ public Matrix4x3d mapnYXnZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYZX() {
+ return mapnYZX(this);
+ }
+ public Matrix4x3d mapnYZX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYZnX() {
+ return mapnYZnX(this);
+ }
+ public Matrix4x3d mapnYZnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYnXZ() {
+ return mapnYnXZ(this);
+ }
+ public Matrix4x3d mapnYnXZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYnXnZ() {
+ return mapnYnXnZ(this);
+ }
+ public Matrix4x3d mapnYnXnZ(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYnZX() {
+ return mapnYnZX(this);
+ }
+ public Matrix4x3d mapnYnZX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnYnZnX() {
+ return mapnYnZnX(this);
+ }
+ public Matrix4x3d mapnYnZnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZXY() {
+ return mapnZXY(this);
+ }
+ public Matrix4x3d mapnZXY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZXnY() {
+ return mapnZXnY(this);
+ }
+ public Matrix4x3d mapnZXnY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZYX() {
+ return mapnZYX(this);
+ }
+ public Matrix4x3d mapnZYX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZYnX() {
+ return mapnZYnX(this);
+ }
+ public Matrix4x3d mapnZYnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZnXY() {
+ return mapnZnXY(this);
+ }
+ public Matrix4x3d mapnZnXY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZnXnY() {
+ return mapnZnXnY(this);
+ }
+ public Matrix4x3d mapnZnXnY(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ double m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZnYX() {
+ return mapnZnYX(this);
+ }
+ public Matrix4x3d mapnZnYX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d mapnZnYnX() {
+ return mapnZnYnX(this);
+ }
+ public Matrix4x3d mapnZnYnX(Matrix4x3d dest) {
+ double m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d negateX() {
+ return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ public Matrix4x3d negateX(Matrix4x3d dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d negateY() {
+ return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ public Matrix4x3d negateY(Matrix4x3d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3d negateZ() {
+ return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ public Matrix4x3d negateZ(Matrix4x3d dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
+ Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
+ Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) &&
+ Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3dStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3dStack.java
new file mode 100644
index 000000000..3e2ef7b22
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3dStack.java
@@ -0,0 +1,186 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2018-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix4x3d} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix4x3dStack} class inherits from {@link Matrix4x3d}, so the current/top matrix is always the
+ * {@link Matrix4x3dStack}/{@link Matrix4x3d} itself. This affects all operations in {@link Matrix4x3d} that take
+ * another {@link Matrix4x3d} as parameter. If a {@link Matrix4x3dStack} is used as argument to those methods, the
+ * effective argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix4x3dStack extends Matrix4x3d {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix4x3dStack(int) constructor}.
+ */
+ private Matrix4x3d[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix4x3dStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix4x3dStack} simply only consists of this
+ * {@link Matrix4x3d}
+ */
+ public Matrix4x3dStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix4x3d[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix4x3d();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix4x3dStack} instance.
+ */
+ public Matrix4x3dStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix4x3dStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix4x3dStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix4x3dStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix4x3d and Matrix4x3dStack:
+ *
+ * - Matrix4x3d.equals(Matrix4x3dStack) is true iff all the 12 matrix elements are equal
+ * - Matrix4x3dStack.equals(Matrix4x3d) is true iff all the 12 matrix elements are equal
+ * - Matrix4x3dStack.equals(Matrix4x3dStack) is true iff all 12 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix4x3dStack) {
+ Matrix4x3dStack other = (Matrix4x3dStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix4x3dStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix4x3d m = new Matrix4x3d();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix4x3dStack cloned = (Matrix4x3dStack) super.clone();
+ Matrix4x3d[] clonedMats = new Matrix4x3d[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix4x3d) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3dc.java
new file mode 100644
index 000000000..b1f4da4bf
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3dc.java
@@ -0,0 +1,3821 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 4x3 matrix of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix4x3dc {
+
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation x=-1
when using the identity matrix.
+ */
+ int PLANE_NX = 0;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation x=1
when using the identity matrix.
+ */
+ int PLANE_PX = 1;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation y=-1
when using the identity matrix.
+ */
+ int PLANE_NY = 2;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation y=1
when using the identity matrix.
+ */
+ int PLANE_PY = 3;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation z=-1
when using the identity matrix.
+ */
+ int PLANE_NZ = 4;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4d)}
+ * identifying the plane with equation z=1
when using the identity matrix.
+ */
+ int PLANE_PZ = 5;
+
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation.
+ */
+ byte PROPERTY_IDENTITY = 1<<2;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation.
+ */
+ byte PROPERTY_TRANSLATION = 1<<3;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the left 3x3 submatrix represents an orthogonal
+ * matrix (i.e. orthonormal basis).
+ */
+ byte PROPERTY_ORTHONORMAL = 1<<4;
+
+ /**
+ * @return the properties of the matrix
+ */
+ int properties();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m01();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m02();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m11();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m12();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m21();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m22();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ double m30();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ double m31();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ double m32();
+
+ /**
+ * Get the current values of this
matrix and store them into the upper 4x3 submatrix of dest
.
+ *
+ * The other elements of dest
will not be modified.
+ *
+ * @see Matrix4d#set4x3(Matrix4x3dc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ Matrix4d get(Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mul(Matrix4x3dc right, Matrix4x3d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the multiplication
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mul(Matrix4x3fc right, Matrix4x3d dest);
+
+ /**
+ * Multiply this matrix, which is assumed to only contain a translation, by the supplied right
matrix and store the result in dest
.
+ *
+ * This method assumes that this
matrix only contains a translation.
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3d mulTranslation(Matrix4x3dc right, Matrix4x3d dest);
+
+ /**
+ * Multiply this matrix, which is assumed to only contain a translation, by the supplied right
matrix and store the result in dest
.
+ *
+ * This method assumes that this
matrix only contains a translation.
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3d mulTranslation(Matrix4x3fc right, Matrix4x3d dest);
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied view
matrix
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix which to multiply this
with
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3d mulOrtho(Matrix4x3dc view, Matrix4x3d dest);
+
+ /**
+ * Multiply this
by the 4x3 matrix with the column vectors (rm00, rm01, rm02)
,
+ * (rm10, rm11, rm12)
, (rm20, rm21, rm22)
and (0, 0, 0)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the specified matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the R
matrix will be applied first!
+ *
+ * @param rm00
+ * the value of the m00 element
+ * @param rm01
+ * the value of the m01 element
+ * @param rm02
+ * the value of the m02 element
+ * @param rm10
+ * the value of the m10 element
+ * @param rm11
+ * the value of the m11 element
+ * @param rm12
+ * the value of the m12 element
+ * @param rm20
+ * the value of the m20 element
+ * @param rm21
+ * the value of the m21 element
+ * @param rm22
+ * the value of the m22 element
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mul3x3(double rm00, double rm01, double rm02, double rm10, double rm11, double rm12, double rm20, double rm21, double rm22, Matrix4x3d dest);
+
+ /**
+ * Component-wise add this
and other
+ * by first multiplying each component of other
by otherFactor
,
+ * adding that to this
and storing the final result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * The matrices this
and other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d fma(Matrix4x3dc other, double otherFactor, Matrix4x3d dest);
+
+ /**
+ * Component-wise add this
and other
+ * by first multiplying each component of other
by otherFactor
,
+ * adding that to this
and storing the final result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * The matrices this
and other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d fma(Matrix4x3fc other, double otherFactor, Matrix4x3d dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d add(Matrix4x3dc other, Matrix4x3d dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d add(Matrix4x3fc other, Matrix4x3d dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d sub(Matrix4x3dc subtrahend, Matrix4x3d dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d sub(Matrix4x3fc subtrahend, Matrix4x3d dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mulComponentWise(Matrix4x3dc other, Matrix4x3d dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ double determinant();
+
+ /**
+ * Invert this
matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d invert(Matrix4x3d dest);
+
+ /**
+ * Invert this
orthographic projection matrix and store the result into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4x3d invertOrtho(Matrix4x3d dest);
+
+ /**
+ * Transpose only the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * All other matrix elements are left unchanged.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d transpose3x3(Matrix4x3d dest);
+
+ /**
+ * Transpose only the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d transpose3x3(Matrix3d dest);
+
+ /**
+ * Get only the translation components (m30, m31, m32)
of this matrix and store them in the given vector xyz
.
+ *
+ * @param dest
+ * will hold the translation components of this matrix
+ * @return dest
+ */
+ Vector3d getTranslation(Vector3d dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
, y
and z
+ * @return dest
+ */
+ Vector3d getScale(Vector3d dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4x3d get(Matrix4x3d dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaternionf#setFromUnnormalized(Matrix4x3dc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getUnnormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are normalized.
+ *
+ * @see Quaternionf#setFromNormalized(Matrix4x3dc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getNormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaterniond#setFromUnnormalized(Matrix4x3dc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getUnnormalizedRotation(Quaterniond dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are normalized.
+ *
+ * @see Quaterniond#setFromNormalized(Matrix4x3dc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getNormalizedRotation(Quaterniond dest);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given {@link DoubleBuffer}.
+ *
+ * @param index
+ * the absolute position into the {@link DoubleBuffer}
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given
+ * FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getFloats(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getFloats(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the elements of this matrix as float values in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getFloats(ByteBuffer buffer);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the elements of this matrix as float values in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getFloats(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix4x3dc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get(double[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied double array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(double[], int)}.
+ *
+ * @see #get(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get(double[] arr);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied float array at the given offset.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store the elements of this matrix as float values in column-major order into the supplied float array.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied array at the given offset,
+ * where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] get4x4(double[] arr, int offset);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied array,
+ * where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(double[], int)}.
+ *
+ * @see #get4x4(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] get4x4(double[] arr);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied array at the given offset,
+ * where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get4x4(float[] arr, int offset);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied array,
+ * where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given float array.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(float[], int)}.
+ *
+ * @see #get4x4(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get4x4(float[] arr);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer get4x4(DoubleBuffer buffer);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get4x4(int index, DoubleBuffer buffer);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(ByteBuffer buffer);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, DoubleBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ DoubleBuffer getTransposed(DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this matrix in row-major order
+ * @return the passed in buffer
+ */
+ DoubleBuffer getTransposed(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in row-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in row-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix as float values in row-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposedFloats(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposedFloats(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix as float values in row-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposedFloats(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this matrix storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix as float values in row-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposedFloats(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix into the supplied float array in row-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ double[] getTransposed(double[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in row-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #getTransposed(double[], int)}.
+ *
+ * @see #getTransposed(double[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ double[] getTransposed(double[] arr);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in that vector.
+ *
+ * @see Vector4d#mul(Matrix4x3dc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4d transform(Vector4d v);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in dest
.
+ *
+ * @see Vector4d#mul(Matrix4x3dc, Vector4d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4d transform(Vector4dc v, Vector4d dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector3dc, Vector3d)}.
+ *
+ * @see #transformPosition(Vector3dc, Vector3d)
+ * @see #transform(Vector4d)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3d transformPosition(Vector3d v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector3d)}.
+ *
+ * @see #transformPosition(Vector3d)
+ * @see #transform(Vector4dc, Vector4d)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPosition(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector3dc, Vector3d)}.
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3d transformDirection(Vector3d v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector3d)}.
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformDirection(Vector3dc v, Vector3d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d scale(Vector3dc xyz, Matrix4x3d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d scale(double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @see #scale(double, double, double, Matrix4x3d)
+ *
+ * @param xyz
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d scale(double xyz, Matrix4x3d dest);
+
+ /**
+ * Apply scaling to this matrix by by scaling the X axis by x
and the Y axis by y
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d scaleXY(double x, double y, Matrix4x3d dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d scaleAround(double sx, double sy, double sz, double ox, double oy, double oz, Matrix4x3d dest);
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4x3d scaleAround(double factor, double ox, double oy, double oz, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d scaleLocal(double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the given axis specified as x, y and z components and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
+ * , the rotation will be applied first!
+ *
+ * @param ang
+ * the angle is in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(double ang, double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateTranslation(double ang, double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix while using (ox, oy, oz)
as the rotation origin,
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateAround(Quaterniondc quat, double ox, double oy, double oz, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateLocal(double ang, double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d translate(Vector3dc offset, Matrix4x3d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d translate(Vector3fc offset, Matrix4x3d dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d translate(double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d translateLocal(Vector3fc offset, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d translateLocal(Vector3dc offset, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d translateLocal(double x, double y, double z, Matrix4x3d dest);
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateX(double ang, Matrix4x3d dest);
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateY(double ang, Matrix4x3d dest);
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateZ(double ang, Matrix4x3d dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateXYZ(double angleX, double angleY, double angleZ, Matrix4x3d dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateZYX(double angleZ, double angleY, double angleX, Matrix4x3d dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateYXZ(double angleY, double angleX, double angleZ, Matrix4x3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(Quaterniondc quat, Matrix4x3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(Quaternionfc quat, Matrix4x3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateTranslation(Quaterniondc quat, Matrix4x3d dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateTranslation(Quaternionfc quat, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaterniondc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaterniondc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateLocal(Quaterniondc quat, Matrix4x3d dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateLocal(Quaternionfc quat, Matrix4x3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4x3d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(AxisAngle4f axisAngle, Matrix4x3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4d} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4d},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4d} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4x3d)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d} (needs to be {@link AxisAngle4d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(AxisAngle4d axisAngle, Matrix4x3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4x3d)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3d#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(double angle, Vector3dc axis, Matrix4x3d dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given angle and axis,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(double, double, double, double, Matrix4x3d)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotate(double angle, Vector3fc axis, Matrix4x3d dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ Vector4d getRow(int row, Vector4d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ Vector3d getColumn(int column, Vector3d dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into the left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d normal(Matrix4x3d dest);
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d normal(Matrix3d dest);
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d cofactor3x3(Matrix3d dest);
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4x3d)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d cofactor3x3(Matrix4x3d dest);
+
+ /**
+ * Normalize the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d normalize3x3(Matrix4x3d dest);
+
+ /**
+ * Normalize the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3d normalize3x3(Matrix3d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
and store the result in dest
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d reflect(double a, double b, double c, double d, Matrix4x3d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d reflect(double nx, double ny, double nz, double px, double py, double pz, Matrix4x3d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane, and store the result in dest
.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaterniondc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d reflect(Quaterniondc orientation, Vector3dc point, Matrix4x3d dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d reflect(Vector3dc normal, Vector3dc point, Matrix4x3d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d ortho(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4x3d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d orthoLH(double left, double right, double bottom, double top, double zNear, double zFar, Matrix4x3d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, boolean, Matrix4x3d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d orthoSymmetric(double width, double height, double zNear, double zFar, Matrix4x3d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, boolean, Matrix4x3d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, boolean zZeroToOne, Matrix4x3d dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d orthoSymmetricLH(double width, double height, double zNear, double zFar, Matrix4x3d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(double, double, double, double, double, double, Matrix4x3d) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(double, double, double, double, double, double, Matrix4x3d)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d ortho2D(double left, double right, double bottom, double top, Matrix4x3d dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(double, double, double, double, double, double, Matrix4x3d) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(double, double, double, double, double, double, Matrix4x3d)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d ortho2DLH(double left, double right, double bottom, double top, Matrix4x3d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3dc, Vector3dc, Vector3dc, Matrix4x3d) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAlong(double, double, double, double, double, double, Matrix4x3d)
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc, Matrix4x3d)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lookAlong(Vector3dc dir, Vector3dc up, Matrix4x3d dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(double, double, double, double, double, double, double, double, double, Matrix4x3d) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double, Matrix4x3d)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4x3d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(double, double, double, double, double, double, double, double, double, Matrix4x3d)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lookAt(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4x3d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(Vector3dc, Vector3dc, Vector3dc, Matrix4x3d)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lookAt(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, Matrix4x3d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(double, double, double, double, double, double, double, double, double, Matrix4x3d)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lookAtLH(Vector3dc eye, Vector3dc center, Vector3dc up, Matrix4x3d dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(Vector3dc, Vector3dc, Vector3dc, Matrix4x3d)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lookAtLH(double eyeX, double eyeY, double eyeZ, double centerX, double centerY, double centerZ, double upX, double upY, double upZ, Matrix4x3d dest);
+
+ /**
+ * Calculate a frustum plane of this
matrix, which
+ * can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given dest
.
+ *
+ * Generally, this method computes the frustum plane in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * The plane normal, which is (a, b, c)
, is directed "inwards" of the frustum.
+ * Any plane/point test using a*x + b*y + c*z + d
therefore will yield a result greater than zero
+ * if the point is within the frustum (i.e. at the positive side of the frustum plane).
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param which
+ * one of the six possible planes, given as numeric constants
+ * {@link #PLANE_NX}, {@link #PLANE_PX},
+ * {@link #PLANE_NY}, {@link #PLANE_PY},
+ * {@link #PLANE_NZ} and {@link #PLANE_PZ}
+ * @param dest
+ * will hold the computed plane equation.
+ * The plane equation will be normalized, meaning that (a, b, c)
will be a unit vector
+ * @return dest
+ */
+ Vector4d frustumPlane(int which, Vector4d dest);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3d inv = new Matrix4x3d(this).invert();
+ * inv.transformDirection(dir.set(0, 0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveZ(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d positiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3d inv = new Matrix4x3d(this).transpose();
+ * inv.transformDirection(dir.set(0, 0, 1)).normalize();
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d normalizedPositiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3d inv = new Matrix4x3d(this).invert();
+ * inv.transformDirection(dir.set(1, 0, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d positiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3d inv = new Matrix4x3d(this).transpose();
+ * inv.transformDirection(dir.set(1, 0, 0)).normalize();
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d normalizedPositiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3d inv = new Matrix4x3d(this).invert();
+ * inv.transformDirection(dir.set(0, 1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector3d)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d positiveY(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3d inv = new Matrix4x3d(this).transpose();
+ * inv.transformDirection(dir.set(0, 1, 0)).normalize();
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d normalizedPositiveY(Vector3d dir);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).invert();
+ * inv.transformPosition(origin.set(0, 0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector3d origin(Vector3d origin);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d shadow(Vector4dc light, double a, double b, double c, double d, Matrix4x3d dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, double a, double b, double c, double d, Matrix4x3d dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d shadow(Vector4dc light, Matrix4x3dc planeTransform, Matrix4x3d dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d shadow(double lightX, double lightY, double lightZ, double lightW, Matrix4x3dc planeTransform, Matrix4x3d dest);
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates, and store the result
+ * in dest
.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3d pick(double x, double y, double width, double height, int[] viewport, Matrix4x3d dest);
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius, dest).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d arcball(double radius, double centerX, double centerY, double centerZ, double angleX, double angleY, Matrix4x3d dest);
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d arcball(double radius, Vector3dc center, double angleX, double angleY, Matrix4x3d dest);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * by this
matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * Reference: http://dev.theomader.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4x3d transformAab(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector3d outMin, Vector3d outMax);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner min
and maximum corner max
+ * by this
matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4x3d transformAab(Vector3dc min, Vector3dc max, Vector3d outMin, Vector3d outMax);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d lerp(Matrix4x3dc other, double t, Matrix4x3d dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the -z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3d().lookAt(new Vector3d(), new Vector3d(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(double, double, double, double, double, double, Matrix4x3d)
+ *
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateTowards(Vector3dc dir, Vector3dc up, Matrix4x3d dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the -z
axis with (dirX, dirY, dirZ)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3d().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3dc, Vector3dc, Matrix4x3d)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d rotateTowards(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Matrix4x3d dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the left 3x3 submatrix of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order X * Y * Z
to obtain the identical matrix.
+ * This means that calling {@link Matrix4x3d#rotateXYZ(double, double, double)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4x3d m = ...; // <- matrix only representing rotation
+ * Matrix4x3d n = new Matrix4x3d();
+ * n.rotateXYZ(m.getEulerAnglesXYZ(new Vector3d()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3d getEulerAnglesXYZ(Vector3d dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the left 3x3 submatrix of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order Z * Y * X
to obtain the identical matrix.
+ * This means that calling {@link Matrix4x3d#rotateZYX(double, double, double)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4x3d m = ...; // <- matrix only representing rotation
+ * Matrix4x3d n = new Matrix4x3d();
+ * n.rotateZYX(m.getEulerAnglesZYX(new Vector3d()));
+ *
+ *
+ * Reference: http://en.wikipedia.org/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3d getEulerAnglesZYX(Vector3d dest);
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d obliqueZ(double a, double b, Matrix4x3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapXZY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapXZnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapXnYnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapXnZY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapXnZnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYXZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYXnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYZX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYZnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYnXZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYnXnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYnZX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapYnZnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZXY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZXnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZYX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZYnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZnXY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZnXnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZnYX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapZnYnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXYnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXZY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXZnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXnYZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXnYnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXnZY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnXnZnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYXZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYXnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYZX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYZnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYnXZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYnXnZ(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYnZX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnYnZnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZXY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZXnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZYX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZYnX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZnXY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZnXnY(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZnYX(Matrix4x3d dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d mapnZnYnX(Matrix4x3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d negateX(Matrix4x3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d negateY(Matrix4x3d dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3d negateZ(Matrix4x3d dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix4x3dc m, double delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3f.java
new file mode 100644
index 000000000..c3c6865e7
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3f.java
@@ -0,0 +1,9838 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+
+/**
+ * Contains the definition of an affine 4x3 matrix (4 columns, 3 rows) of floats, and associated functions to transform
+ * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this:
+ *
+ * m00 m10 m20 m30
+ * m01 m11 m21 m31
+ * m02 m12 m22 m32
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Matrix4x3f implements Externalizable, Cloneable, Matrix4x3fc {
+
+ private static final long serialVersionUID = 1L;
+
+ float m00, m01, m02;
+ float m10, m11, m12;
+ float m20, m21, m22;
+ float m30, m31, m32;
+
+ int properties;
+
+ /**
+ * Create a new {@link Matrix4x3f} and set it to {@link #identity() identity}.
+ */
+ public Matrix4x3f() {
+ m00 = 1.0f;
+ m11 = 1.0f;
+ m22 = 1.0f;
+ properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ }
+
+ /**
+ * Create a new {@link Matrix4x3f} by setting its left 3x3 submatrix to the values of the given {@link Matrix3fc}
+ * and the rest to identity.
+ *
+ * @param mat
+ * the {@link Matrix3fc}
+ */
+ public Matrix4x3f(Matrix3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new {@link Matrix4x3f} and make it a copy of the given matrix.
+ *
+ * @param mat
+ * the {@link Matrix4x3fc} to copy the values from
+ */
+ public Matrix4x3f(Matrix4x3fc mat) {
+ set(mat);
+ }
+
+ /**
+ * Create a new 4x4 matrix using the supplied float values.
+ *
+ * @param m00
+ * the value of m00
+ * @param m01
+ * the value of m01
+ * @param m02
+ * the value of m02
+ * @param m10
+ * the value of m10
+ * @param m11
+ * the value of m11
+ * @param m12
+ * the value of m12
+ * @param m20
+ * the value of m20
+ * @param m21
+ * the value of m21
+ * @param m22
+ * the value of m22
+ * @param m30
+ * the value of m30
+ * @param m31
+ * the value of m31
+ * @param m32
+ * the value of m32
+ */
+ public Matrix4x3f(float m00, float m01, float m02,
+ float m10, float m11, float m12,
+ float m20, float m21, float m22,
+ float m30, float m31, float m32) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ this.m30 = m30;
+ this.m31 = m31;
+ this.m32 = m32;
+ determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4x3f} by reading its 12 float components from the given {@link FloatBuffer}
+ * at the buffer's current position.
+ *
+ * That FloatBuffer is expected to hold the values in column-major order.
+ *
+ * The buffer's position will not be changed by this method.
+ *
+ * @param buffer
+ * the {@link FloatBuffer} to read the matrix values from
+ */
+ public Matrix4x3f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ determineProperties();
+ }
+
+ /**
+ * Create a new {@link Matrix4x3f} and initialize its four columns using the supplied vectors.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ */
+ public Matrix4x3f(Vector3fc col0, Vector3fc col1, Vector3fc col2, Vector3fc col3) {
+ set(col0, col1, col2, col3).
+ determineProperties();
+ }
+
+ /**
+ * Assume the given properties about this matrix.
+ *
+ * Use one or multiple of 0, {@link Matrix4x3fc#PROPERTY_IDENTITY},
+ * {@link Matrix4x3fc#PROPERTY_TRANSLATION}, {@link Matrix4x3fc#PROPERTY_ORTHONORMAL}.
+ *
+ * @param properties
+ * bitset of the properties to assume about this matrix
+ * @return this
+ */
+ public Matrix4x3f assume(int properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ /**
+ * Compute and set the matrix properties returned by {@link #properties()} based
+ * on the current matrix element values.
+ *
+ * @return this
+ */
+ public Matrix4x3f determineProperties() {
+ int properties = 0;
+ if (m00 == 1.0f && m01 == 0.0f && m02 == 0.0f && m10 == 0.0f && m11 == 1.0f && m12 == 0.0f
+ && m20 == 0.0f && m21 == 0.0f && m22 == 1.0f) {
+ properties |= PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ if (m30 == 0.0f && m31 == 0.0f && m32 == 0.0f)
+ properties |= PROPERTY_IDENTITY;
+ }
+ /*
+ * We do not determine orthogonality, since it would require arbitrary epsilons
+ * and is rather expensive (6 dot products) in the worst case.
+ */
+ this.properties = properties;
+ return this;
+ }
+
+ public int properties() {
+ return properties;
+ }
+
+ public float m00() {
+ return m00;
+ }
+ public float m01() {
+ return m01;
+ }
+ public float m02() {
+ return m02;
+ }
+ public float m10() {
+ return m10;
+ }
+ public float m11() {
+ return m11;
+ }
+ public float m12() {
+ return m12;
+ }
+ public float m20() {
+ return m20;
+ }
+ public float m21() {
+ return m21;
+ }
+ public float m22() {
+ return m22;
+ }
+ public float m30() {
+ return m30;
+ }
+ public float m31() {
+ return m31;
+ }
+ public float m32() {
+ return m32;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m00(float m00) {
+ this.m00 = m00;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m00 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m01(float m01) {
+ this.m01 = m01;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m01 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m02(float m02) {
+ this.m02 = m02;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m02 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m10(float m10) {
+ this.m10 = m10;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m10 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m11(float m11) {
+ this.m11 = m11;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m11 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m12(float m12) {
+ this.m12 = m12;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m12 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m20(float m20) {
+ this.m20 = m20;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m20 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m21(float m21) {
+ this.m21 = m21;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m21 != 0.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m22(float m22) {
+ this.m22 = m22;
+ properties &= ~PROPERTY_ORTHONORMAL;
+ if (m22 != 1.0f)
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m30(float m30) {
+ this.m30 = m30;
+ if (m30 != 0.0f)
+ properties &= ~PROPERTY_IDENTITY;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m31(float m31) {
+ this.m31 = m31;
+ if (m31 != 0.0f)
+ properties &= ~PROPERTY_IDENTITY;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ public Matrix4x3f m32(float m32) {
+ this.m32 = m32;
+ if (m32 != 0.0f)
+ properties &= ~PROPERTY_IDENTITY;
+ return this;
+ }
+
+ Matrix4x3f _properties(int properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ /**
+ * Set the value of the matrix element at column 0 and row 0 without updating the properties of the matrix.
+ *
+ * @param m00
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m00(float m00) {
+ this.m00 = m00;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 1 without updating the properties of the matrix.
+ *
+ * @param m01
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m01(float m01) {
+ this.m01 = m01;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 0 and row 2 without updating the properties of the matrix.
+ *
+ * @param m02
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m02(float m02) {
+ this.m02 = m02;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 0 without updating the properties of the matrix.
+ *
+ * @param m10
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m10(float m10) {
+ this.m10 = m10;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 1 without updating the properties of the matrix.
+ *
+ * @param m11
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m11(float m11) {
+ this.m11 = m11;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 1 and row 2 without updating the properties of the matrix.
+ *
+ * @param m12
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m12(float m12) {
+ this.m12 = m12;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 0 without updating the properties of the matrix.
+ *
+ * @param m20
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m20(float m20) {
+ this.m20 = m20;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 1 without updating the properties of the matrix.
+ *
+ * @param m21
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m21(float m21) {
+ this.m21 = m21;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 2 and row 2 without updating the properties of the matrix.
+ *
+ * @param m22
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m22(float m22) {
+ this.m22 = m22;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 0 without updating the properties of the matrix.
+ *
+ * @param m30
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m30(float m30) {
+ this.m30 = m30;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 1 without updating the properties of the matrix.
+ *
+ * @param m31
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m31(float m31) {
+ this.m31 = m31;
+ return this;
+ }
+ /**
+ * Set the value of the matrix element at column 3 and row 2 without updating the properties of the matrix.
+ *
+ * @param m32
+ * the new value
+ * @return this
+ */
+ Matrix4x3f _m32(float m32) {
+ this.m32 = m32;
+ return this;
+ }
+
+ /**
+ * Reset this matrix to the identity.
+ *
+ * Please note that if a call to {@link #identity()} is immediately followed by a call to:
+ * {@link #translate(float, float, float) translate},
+ * {@link #rotate(float, float, float, float) rotate},
+ * {@link #scale(float, float, float) scale},
+ * {@link #ortho(float, float, float, float, float, float) ortho},
+ * {@link #ortho2D(float, float, float, float) ortho2D},
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt},
+ * {@link #lookAlong(float, float, float, float, float, float) lookAlong},
+ * or any of their overloads, then the call to {@link #identity()} can be omitted and the subsequent call replaced with:
+ * {@link #translation(float, float, float) translation},
+ * {@link #rotation(float, float, float, float) rotation},
+ * {@link #scaling(float, float, float) scaling},
+ * {@link #setOrtho(float, float, float, float, float, float) setOrtho},
+ * {@link #setOrtho2D(float, float, float, float) setOrtho2D},
+ * {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt},
+ * {@link #setLookAlong(float, float, float, float, float, float) setLookAlong},
+ * or any of their overloads.
+ *
+ * @return this
+ */
+ public Matrix4x3f identity() {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return this;
+ MemUtil.INSTANCE.identity(this);
+ properties = PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Store the values of the given matrix m
into this
matrix.
+ *
+ * @see #Matrix4x3f(Matrix4x3fc)
+ * @see #get(Matrix4x3f)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4x3f set(Matrix4x3fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ m30 = m.m30();
+ m31 = m.m31();
+ m32 = m.m32();
+ properties = m.properties();
+ return this;
+ }
+
+ /**
+ * Store the values of the upper 4x3 submatrix of m
into this
matrix.
+ *
+ * @see Matrix4fc#get4x3(Matrix4x3f)
+ *
+ * @param m
+ * the matrix to copy the values from
+ * @return this
+ */
+ public Matrix4x3f set(Matrix4fc m) {
+ m00 = m.m00();
+ m01 = m.m01();
+ m02 = m.m02();
+ m10 = m.m10();
+ m11 = m.m11();
+ m12 = m.m12();
+ m20 = m.m20();
+ m21 = m.m21();
+ m22 = m.m22();
+ m30 = m.m30();
+ m31 = m.m31();
+ m32 = m.m32();
+ properties = m.properties() & (PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return this;
+ }
+
+ public Matrix4f get(Matrix4f dest) {
+ return dest.set4x3(this);
+ }
+
+ public Matrix4d get(Matrix4d dest) {
+ return dest.set4x3(this);
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3f} to the given {@link Matrix3fc}
+ * and the rest to identity.
+ *
+ * @see #Matrix4x3f(Matrix3fc)
+ *
+ * @param mat
+ * the {@link Matrix3fc}
+ * @return this
+ */
+ public Matrix4x3f set(Matrix3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ return determineProperties();
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Matrix4x3f set(AxisAngle4f axisAngle) {
+ float x = axisAngle.x;
+ float y = axisAngle.y;
+ float z = axisAngle.z;
+ float angle = axisAngle.angle;
+ float n = Math.sqrt(x*x + y*y + z*z);
+ n = 1/n;
+ x *= n;
+ y *= n;
+ z *= n;
+ float s = Math.sin(angle);
+ float c = Math.cosFromSin(s, angle);
+ float omc = 1.0f - c;
+ m00 = (float)(c + x*x*omc);
+ m11 = (float)(c + y*y*omc);
+ m22 = (float)(c + z*z*omc);
+ float tmp1 = x*y*omc;
+ float tmp2 = z*s;
+ m10 = (float)(tmp1 - tmp2);
+ m01 = (float)(tmp1 + tmp2);
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = (float)(tmp1 + tmp2);
+ m02 = (float)(tmp1 - tmp2);
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = (float)(tmp1 - tmp2);
+ m12 = (float)(tmp1 + tmp2);
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation specified by the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Matrix4x3f set(AxisAngle4d axisAngle) {
+ double x = axisAngle.x;
+ double y = axisAngle.y;
+ double z = axisAngle.z;
+ double angle = axisAngle.angle;
+ double n = Math.sqrt(x*x + y*y + z*z);
+ n = 1/n;
+ x *= n;
+ y *= n;
+ z *= n;
+ double s = Math.sin(angle);
+ double c = Math.cosFromSin(s, angle);
+ double omc = 1.0 - c;
+ m00 = (float)(c + x*x*omc);
+ m11 = (float)(c + y*y*omc);
+ m22 = (float)(c + z*z*omc);
+ double tmp1 = x*y*omc;
+ double tmp2 = z*s;
+ m10 = (float)(tmp1 - tmp2);
+ m01 = (float)(tmp1 + tmp2);
+ tmp1 = x*z*omc;
+ tmp2 = y*s;
+ m20 = (float)(tmp1 + tmp2);
+ m02 = (float)(tmp1 - tmp2);
+ tmp1 = y*z*omc;
+ tmp2 = x*s;
+ m21 = (float)(tmp1 - tmp2);
+ m12 = (float)(tmp1 + tmp2);
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaternionfc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param q
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3f set(Quaternionfc q) {
+ return rotation(q);
+ }
+
+ /**
+ * Set this matrix to be equivalent to the rotation - and possibly scaling - specified by the given {@link Quaterniondc}.
+ *
+ * This method is equivalent to calling: rotation(q)
+ *
+ * @param q
+ * the {@link Quaterniondc}
+ * @return this
+ */
+ public Matrix4x3f set(Quaterniondc q) {
+ double w2 = q.w() * q.w();
+ double x2 = q.x() * q.x();
+ double y2 = q.y() * q.y();
+ double z2 = q.z() * q.z();
+ double zw = q.z() * q.w();
+ double xy = q.x() * q.y();
+ double xz = q.x() * q.z();
+ double yw = q.y() * q.w();
+ double yz = q.y() * q.z();
+ double xw = q.x() * q.w();
+ m00 = (float) (w2 + x2 - z2 - y2);
+ m01 = (float) (xy + zw + zw + xy);
+ m02 = (float) (xz - yw + xz - yw);
+ m10 = (float) (-zw + xy - zw + xy);
+ m11 = (float) (y2 - z2 + w2 - x2);
+ m12 = (float) (yz + yz + xw + xw);
+ m20 = (float) (yw + xz + xz + yw);
+ m21 = (float) (yz + yz - xw - xw);
+ m22 = (float) (z2 - y2 - x2 + w2);
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set the four columns of this matrix to the supplied vectors, respectively.
+ *
+ * @param col0
+ * the first column
+ * @param col1
+ * the second column
+ * @param col2
+ * the third column
+ * @param col3
+ * the fourth column
+ * @return this
+ */
+ public Matrix4x3f set(Vector3fc col0, Vector3fc col1, Vector3fc col2, Vector3fc col3) {
+ this.m00 = col0.x();
+ this.m01 = col0.y();
+ this.m02 = col0.z();
+ this.m10 = col1.x();
+ this.m11 = col1.y();
+ this.m12 = col1.z();
+ this.m20 = col2.x();
+ this.m21 = col2.y();
+ this.m22 = col2.z();
+ this.m30 = col3.x();
+ this.m31 = col3.y();
+ this.m32 = col3.z();
+ return determineProperties();
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3f} to that of the given {@link Matrix4x3fc}
+ * and don't change the other elements.
+ *
+ * @param mat
+ * the {@link Matrix4x3fc}
+ * @return this
+ */
+ public Matrix4x3f set3x3(Matrix4x3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ properties &= mat.properties();
+ return this;
+ }
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in this
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @return this
+ */
+ public Matrix4x3f mul(Matrix4x3fc right) {
+ return mul(right, this);
+ }
+
+ public Matrix4x3f mul(Matrix4x3fc right, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.set(right);
+ else if ((right.properties() & PROPERTY_IDENTITY) != 0)
+ return dest.set(this);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return mulTranslation(right, dest);
+ return mulGeneric(right, dest);
+ }
+ private Matrix4x3f mulGeneric(Matrix4x3fc right, Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ float m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ float rm00 = right.m00(), rm01 = right.m01(), rm02 = right.m02();
+ float rm10 = right.m10(), rm11 = right.m11(), rm12 = right.m12();
+ float rm20 = right.m20(), rm21 = right.m21(), rm22 = right.m22();
+ float rm30 = right.m30(), rm31 = right.m31(), rm32 = right.m32();
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m30(Math.fma(m00, rm30, Math.fma(m10, rm31, Math.fma(m20, rm32, m30))))
+ ._m31(Math.fma(m01, rm30, Math.fma(m11, rm31, Math.fma(m21, rm32, m31))))
+ ._m32(Math.fma(m02, rm30, Math.fma(m12, rm31, Math.fma(m22, rm32, m32))))
+ ._properties(properties & right.properties() & PROPERTY_ORTHONORMAL);
+ }
+
+ public Matrix4x3f mulTranslation(Matrix4x3fc right, Matrix4x3f dest) {
+ return dest
+ ._m00(right.m00())
+ ._m01(right.m01())
+ ._m02(right.m02())
+ ._m10(right.m10())
+ ._m11(right.m11())
+ ._m12(right.m12())
+ ._m20(right.m20())
+ ._m21(right.m21())
+ ._m22(right.m22())
+ ._m30(right.m30() + m30)
+ ._m31(right.m31() + m31)
+ ._m32(right.m32() + m32)
+ ._properties(right.properties() & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied view
matrix.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix which to multiply this
with
+ * @return this
+ */
+ public Matrix4x3f mulOrtho(Matrix4x3fc view) {
+ return mulOrtho(view, this);
+ }
+
+ public Matrix4x3f mulOrtho(Matrix4x3fc view, Matrix4x3f dest) {
+ float nm00 = m00 * view.m00();
+ float nm01 = m11 * view.m01();
+ float nm02 = m22 * view.m02();
+ float nm10 = m00 * view.m10();
+ float nm11 = m11 * view.m11();
+ float nm12 = m22 * view.m12();
+ float nm20 = m00 * view.m20();
+ float nm21 = m11 * view.m21();
+ float nm22 = m22 * view.m22();
+ float nm30 = m00 * view.m30() + m30;
+ float nm31 = m11 * view.m31() + m31;
+ float nm32 = m22 * view.m32() + m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = (this.properties & view.properties() & PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+
+ /**
+ * Multiply this
by the 4x3 matrix with the column vectors (rm00, rm01, rm02)
,
+ * (rm10, rm11, rm12)
, (rm20, rm21, rm22)
and (0, 0, 0)
.
+ *
+ * If M
is this
matrix and R
the specified matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the R
matrix will be applied first!
+ *
+ * @param rm00
+ * the value of the m00 element
+ * @param rm01
+ * the value of the m01 element
+ * @param rm02
+ * the value of the m02 element
+ * @param rm10
+ * the value of the m10 element
+ * @param rm11
+ * the value of the m11 element
+ * @param rm12
+ * the value of the m12 element
+ * @param rm20
+ * the value of the m20 element
+ * @param rm21
+ * the value of the m21 element
+ * @param rm22
+ * the value of the m22 element
+ * @return this
+ */
+ public Matrix4x3f mul3x3(
+ float rm00, float rm01, float rm02,
+ float rm10, float rm11, float rm12,
+ float rm20, float rm21, float rm22) {
+ return mul3x3(rm00, rm01, rm02, rm10, rm11, rm12, rm20, rm21, rm22, this);
+ }
+ public Matrix4x3f mul3x3(
+ float rm00, float rm01, float rm02,
+ float rm10, float rm11, float rm12,
+ float rm20, float rm21, float rm22,
+ Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ float m20 = this.m20, m21 = this.m21, m22 = this.m22;
+ return dest
+ ._m00(Math.fma(m00, rm00, Math.fma(m10, rm01, m20 * rm02)))
+ ._m01(Math.fma(m01, rm00, Math.fma(m11, rm01, m21 * rm02)))
+ ._m02(Math.fma(m02, rm00, Math.fma(m12, rm01, m22 * rm02)))
+ ._m10(Math.fma(m00, rm10, Math.fma(m10, rm11, m20 * rm12)))
+ ._m11(Math.fma(m01, rm10, Math.fma(m11, rm11, m21 * rm12)))
+ ._m12(Math.fma(m02, rm10, Math.fma(m12, rm11, m22 * rm12)))
+ ._m20(Math.fma(m00, rm20, Math.fma(m10, rm21, m20 * rm22)))
+ ._m21(Math.fma(m01, rm20, Math.fma(m11, rm21, m21 * rm22)))
+ ._m22(Math.fma(m02, rm20, Math.fma(m12, rm21, m22 * rm22)))
+ ._m30(m30)
+ ._m31(m31)
+ ._m32(m32)
+ ._properties(0);
+ }
+
+ /**
+ * Component-wise add this
and other
+ * by first multiplying each component of other
by otherFactor
and
+ * adding that result to this
.
+ *
+ * The matrix other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's components
+ * @return this
+ */
+ public Matrix4x3f fma(Matrix4x3fc other, float otherFactor) {
+ return fma(other, otherFactor, this);
+ }
+
+ public Matrix4x3f fma(Matrix4x3fc other, float otherFactor, Matrix4x3f dest) {
+ dest
+ ._m00(Math.fma(other.m00(), otherFactor, m00))
+ ._m01(Math.fma(other.m01(), otherFactor, m01))
+ ._m02(Math.fma(other.m02(), otherFactor, m02))
+ ._m10(Math.fma(other.m10(), otherFactor, m10))
+ ._m11(Math.fma(other.m11(), otherFactor, m11))
+ ._m12(Math.fma(other.m12(), otherFactor, m12))
+ ._m20(Math.fma(other.m20(), otherFactor, m20))
+ ._m21(Math.fma(other.m21(), otherFactor, m21))
+ ._m22(Math.fma(other.m22(), otherFactor, m22))
+ ._m30(Math.fma(other.m30(), otherFactor, m30))
+ ._m31(Math.fma(other.m31(), otherFactor, m31))
+ ._m32(Math.fma(other.m32(), otherFactor, m32))
+ ._properties(0);
+ return dest;
+ }
+
+ /**
+ * Component-wise add this
and other
.
+ *
+ * @param other
+ * the other addend
+ * @return this
+ */
+ public Matrix4x3f add(Matrix4x3fc other) {
+ return add(other, this);
+ }
+
+ public Matrix4x3f add(Matrix4x3fc other, Matrix4x3f dest) {
+ dest.m00 = m00 + other.m00();
+ dest.m01 = m01 + other.m01();
+ dest.m02 = m02 + other.m02();
+ dest.m10 = m10 + other.m10();
+ dest.m11 = m11 + other.m11();
+ dest.m12 = m12 + other.m12();
+ dest.m20 = m20 + other.m20();
+ dest.m21 = m21 + other.m21();
+ dest.m22 = m22 + other.m22();
+ dest.m30 = m30 + other.m30();
+ dest.m31 = m31 + other.m31();
+ dest.m32 = m32 + other.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Component-wise subtract subtrahend
from this
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @return this
+ */
+ public Matrix4x3f sub(Matrix4x3fc subtrahend) {
+ return sub(subtrahend, this);
+ }
+
+ public Matrix4x3f sub(Matrix4x3fc subtrahend, Matrix4x3f dest) {
+ dest.m00 = m00 - subtrahend.m00();
+ dest.m01 = m01 - subtrahend.m01();
+ dest.m02 = m02 - subtrahend.m02();
+ dest.m10 = m10 - subtrahend.m10();
+ dest.m11 = m11 - subtrahend.m11();
+ dest.m12 = m12 - subtrahend.m12();
+ dest.m20 = m20 - subtrahend.m20();
+ dest.m21 = m21 - subtrahend.m21();
+ dest.m22 = m22 - subtrahend.m22();
+ dest.m30 = m30 - subtrahend.m30();
+ dest.m31 = m31 - subtrahend.m31();
+ dest.m32 = m32 - subtrahend.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Component-wise multiply this
by other
.
+ *
+ * @param other
+ * the other matrix
+ * @return this
+ */
+ public Matrix4x3f mulComponentWise(Matrix4x3fc other) {
+ return mulComponentWise(other, this);
+ }
+
+ public Matrix4x3f mulComponentWise(Matrix4x3fc other, Matrix4x3f dest) {
+ dest.m00 = m00 * other.m00();
+ dest.m01 = m01 * other.m01();
+ dest.m02 = m02 * other.m02();
+ dest.m10 = m10 * other.m10();
+ dest.m11 = m11 * other.m11();
+ dest.m12 = m12 * other.m12();
+ dest.m20 = m20 * other.m20();
+ dest.m21 = m21 * other.m21();
+ dest.m22 = m22 * other.m22();
+ dest.m30 = m30 * other.m30();
+ dest.m31 = m31 * other.m31();
+ dest.m32 = m32 * other.m32();
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Set the values within this matrix to the supplied float values. The matrix will look like this:
+ *
+ * m00, m10, m20, m30
+ * m01, m11, m21, m31
+ * m02, m12, m22, m32
+ *
+ * @param m00
+ * the new value of m00
+ * @param m01
+ * the new value of m01
+ * @param m02
+ * the new value of m02
+ * @param m10
+ * the new value of m10
+ * @param m11
+ * the new value of m11
+ * @param m12
+ * the new value of m12
+ * @param m20
+ * the new value of m20
+ * @param m21
+ * the new value of m21
+ * @param m22
+ * the new value of m22
+ * @param m30
+ * the new value of m30
+ * @param m31
+ * the new value of m31
+ * @param m32
+ * the new value of m32
+ * @return this
+ */
+ public Matrix4x3f set(float m00, float m01, float m02,
+ float m10, float m11, float m12,
+ float m20, float m21, float m22,
+ float m30, float m31, float m32) {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+ this.m30 = m30;
+ this.m31 = m31;
+ this.m32 = m32;
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 3, 6, 9
+ * 1, 4, 7, 10
+ * 2, 5, 8, 11
+ *
+ * @see #set(float[])
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @param off
+ * the offset into the array
+ * @return this
+ */
+ public Matrix4x3f set(float m[], int off) {
+ MemUtil.INSTANCE.copy(m, off, this);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values in the matrix using a float array that contains the matrix elements in column-major order.
+ *
+ * The results will look like this:
+ *
+ * 0, 3, 6, 9
+ * 1, 4, 7, 10
+ * 2, 5, 8, 11
+ *
+ * @see #set(float[], int)
+ *
+ * @param m
+ * the array to read the matrix values from
+ * @return this
+ */
+ public Matrix4x3f set(float m[]) {
+ return set(m, 0);
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at its current position.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link FloatBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The FloatBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the FloatBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * the FloatBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+
+ /**
+ * Set the values of this matrix by reading 12 float values from the given {@link ByteBuffer} in column-major order,
+ * starting at the specified absolute buffer position/index.
+ *
+ * The ByteBuffer is expected to contain the values in column-major order.
+ *
+ * The position of the ByteBuffer will not be changed by this method.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * the ByteBuffer to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return determineProperties();
+ }
+ /**
+ * Set the values of this matrix by reading 12 float values from off-heap memory in column-major order,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the matrix values from in column-major order
+ * @return this
+ */
+ public Matrix4x3f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return determineProperties();
+ }
+
+ public float determinant() {
+ return (m00 * m11 - m01 * m10) * m22
+ + (m02 * m10 - m00 * m12) * m21
+ + (m01 * m12 - m02 * m11) * m20;
+ }
+
+ public Matrix4x3f invert(Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return invertOrthonormal(dest);
+ return invertGeneric(dest);
+ }
+ private Matrix4x3f invertGeneric(Matrix4x3f dest) {
+ float m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
+ float m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
+ float s = 1.0f / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20);
+ float m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
+ float m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
+ float m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
+ float m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
+ float nm00 = (m11m22 - m12m21) * s;
+ float nm01 = (m21m02 - m22m01) * s;
+ float nm02 = (m12m01 - m11m02) * s;
+ float nm10 = (m12m20 - m10m22) * s;
+ float nm11 = (m22m00 - m20m02) * s;
+ float nm12 = (m10m02 - m12m00) * s;
+ float nm20 = (m10m21 - m11m20) * s;
+ float nm21 = (m20m01 - m21m00) * s;
+ float nm22 = (m11m00 - m10m01) * s;
+ float nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s;
+ float nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
+ float nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = 0;
+ return dest;
+ }
+ private Matrix4x3f invertOrthonormal(Matrix4x3f dest) {
+ float nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
+ float nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
+ float nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
+ float m01 = this.m01;
+ float m02 = this.m02;
+ float m12 = this.m12;
+ dest.m00 = m00;
+ dest.m01 = m10;
+ dest.m02 = m20;
+ dest.m10 = m01;
+ dest.m11 = m11;
+ dest.m12 = m21;
+ dest.m20 = m02;
+ dest.m21 = m12;
+ dest.m22 = m22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = PROPERTY_ORTHONORMAL;
+ return dest;
+ }
+
+ public Matrix4f invert(Matrix4f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return invertOrthonormal(dest);
+ return invertGeneric(dest);
+ }
+ private Matrix4f invertGeneric(Matrix4f dest) {
+ float m11m00 = m00 * m11, m10m01 = m01 * m10, m10m02 = m02 * m10;
+ float m12m00 = m00 * m12, m12m01 = m01 * m12, m11m02 = m02 * m11;
+ float s = 1.0f / ((m11m00 - m10m01) * m22 + (m10m02 - m12m00) * m21 + (m12m01 - m11m02) * m20);
+ float m10m22 = m10 * m22, m10m21 = m10 * m21, m11m22 = m11 * m22;
+ float m11m20 = m11 * m20, m12m21 = m12 * m21, m12m20 = m12 * m20;
+ float m20m02 = m20 * m02, m20m01 = m20 * m01, m21m02 = m21 * m02;
+ float m21m00 = m21 * m00, m22m01 = m22 * m01, m22m00 = m22 * m00;
+ float nm00 = (m11m22 - m12m21) * s;
+ float nm01 = (m21m02 - m22m01) * s;
+ float nm02 = (m12m01 - m11m02) * s;
+ float nm10 = (m12m20 - m10m22) * s;
+ float nm11 = (m22m00 - m20m02) * s;
+ float nm12 = (m10m02 - m12m00) * s;
+ float nm20 = (m10m21 - m11m20) * s;
+ float nm21 = (m20m01 - m21m00) * s;
+ float nm22 = (m11m00 - m10m01) * s;
+ float nm30 = (m10m22 * m31 - m10m21 * m32 + m11m20 * m32 - m11m22 * m30 + m12m21 * m30 - m12m20 * m31) * s;
+ float nm31 = (m20m02 * m31 - m20m01 * m32 + m21m00 * m32 - m21m02 * m30 + m22m01 * m30 - m22m00 * m31) * s;
+ float nm32 = (m11m02 * m30 - m12m01 * m30 + m12m00 * m31 - m10m02 * m31 + m10m01 * m32 - m11m00 * m32) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m03 = 0.0f;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m13 = 0.0f;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m23 = 0.0f;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.m33 = 0.0f;
+ dest.properties = 0;
+ return dest;
+ }
+ private Matrix4f invertOrthonormal(Matrix4f dest) {
+ float nm30 = -(m00 * m30 + m01 * m31 + m02 * m32);
+ float nm31 = -(m10 * m30 + m11 * m31 + m12 * m32);
+ float nm32 = -(m20 * m30 + m21 * m31 + m22 * m32);
+ float m01 = this.m01;
+ float m02 = this.m02;
+ float m12 = this.m12;
+ dest.m00 = m00;
+ dest.m01 = m10;
+ dest.m02 = m20;
+ dest.m03 = 0.0f;
+ dest.m10 = m01;
+ dest.m11 = m11;
+ dest.m12 = m21;
+ dest.m13 = 0.0f;
+ dest.m20 = m02;
+ dest.m21 = m12;
+ dest.m22 = m22;
+ dest.m23 = 0.0f;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.m33 = 0.0f;
+ dest.properties = PROPERTY_ORTHONORMAL;
+ return dest;
+ }
+
+ /**
+ * Invert this matrix.
+ *
+ * @return this
+ */
+ public Matrix4x3f invert() {
+ return invert(this);
+ }
+
+ public Matrix4x3f invertOrtho(Matrix4x3f dest) {
+ float invM00 = 1.0f / m00;
+ float invM11 = 1.0f / m11;
+ float invM22 = 1.0f / m22;
+ dest.set(invM00, 0, 0,
+ 0, invM11, 0,
+ 0, 0, invM22,
+ -m30 * invM00, -m31 * invM11, -m32 * invM22);
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Invert this
orthographic projection matrix.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @return this
+ */
+ public Matrix4x3f invertOrtho() {
+ return invertOrtho(this);
+ }
+
+ /**
+ * Transpose only the left 3x3 submatrix of this matrix and set the rest of the matrix elements to identity.
+ *
+ * @return this
+ */
+ public Matrix4x3f transpose3x3() {
+ return transpose3x3(this);
+ }
+
+ public Matrix4x3f transpose3x3(Matrix4x3f dest) {
+ float nm00 = m00;
+ float nm01 = m10;
+ float nm02 = m20;
+ float nm10 = m01;
+ float nm11 = m11;
+ float nm12 = m21;
+ float nm20 = m02;
+ float nm21 = m12;
+ float nm22 = m22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.properties = properties;
+ return dest;
+ }
+
+ public Matrix3f transpose3x3(Matrix3f dest) {
+ dest.m00(m00);
+ dest.m01(m10);
+ dest.m02(m20);
+ dest.m10(m01);
+ dest.m11(m11);
+ dest.m12(m21);
+ dest.m20(m02);
+ dest.m21(m12);
+ dest.m22(m22);
+ return dest;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to post-multiply a translation transformation directly to a
+ * matrix, use {@link #translate(float, float, float) translate()} instead.
+ *
+ * @see #translate(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3f translation(float x, float y, float z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ m30 = x;
+ m31 = y;
+ m32 = z;
+ properties = PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple translation matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional translation.
+ *
+ * In order to post-multiply a translation transformation directly to a
+ * matrix, use {@link #translate(Vector3fc) translate()} instead.
+ *
+ * @see #translate(float, float, float)
+ *
+ * @param offset
+ * the offsets in x, y and z to translate
+ * @return this
+ */
+ public Matrix4x3f translation(Vector3fc offset) {
+ return translation(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the given values (x, y, z)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(float, float, float)}.
+ * To apply a translation, use {@link #translate(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ * @see #translate(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3f setTranslation(float x, float y, float z) {
+ m30 = x;
+ m31 = y;
+ m32 = z;
+ properties &= ~(PROPERTY_IDENTITY);
+ return this;
+ }
+
+ /**
+ * Set only the translation components (m30, m31, m32)
of this matrix to the values (xyz.x, xyz.y, xyz.z)
.
+ *
+ * To build a translation matrix instead, use {@link #translation(Vector3fc)}.
+ * To apply a translation, use {@link #translate(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ * @see #translate(Vector3fc)
+ *
+ * @param xyz
+ * the units to translate in (x, y, z)
+ * @return this
+ */
+ public Matrix4x3f setTranslation(Vector3fc xyz) {
+ return setTranslation(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ public Vector3f getTranslation(Vector3f dest) {
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ return dest;
+ }
+
+ public Vector3f getScale(Vector3f dest) {
+ dest.x = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ dest.y = Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ dest.z = Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this matrix.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ String str = toString(Options.NUMBER_FORMAT);
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ /**
+ * Return a string representation of this matrix by formatting the matrix elements with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the matrix values with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return Runtime.format(m00, formatter) + " " + Runtime.format(m10, formatter) + " " + Runtime.format(m20, formatter) + " " + Runtime.format(m30, formatter) + "\n"
+ + Runtime.format(m01, formatter) + " " + Runtime.format(m11, formatter) + " " + Runtime.format(m21, formatter) + " " + Runtime.format(m31, formatter) + "\n"
+ + Runtime.format(m02, formatter) + " " + Runtime.format(m12, formatter) + " " + Runtime.format(m22, formatter) + " " + Runtime.format(m32, formatter) + "\n";
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link #set(Matrix4x3fc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see #set(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix4x3f get(Matrix4x3f dest) {
+ return dest.set(this);
+ }
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * This is the reverse method of {@link Matrix4x3d#set(Matrix4x3fc)} and allows to obtain
+ * intermediate calculation results when chaining multiple transformations.
+ *
+ * @see Matrix4x3d#set(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ public Matrix4x3d get(Matrix4x3d dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4f getRotation(AxisAngle4f dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4d getRotation(AxisAngle4d dest) {
+ return dest.set(this);
+ }
+
+ public Quaternionf getUnnormalizedRotation(Quaternionf dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaternionf getNormalizedRotation(Quaternionf dest) {
+ return dest.setFromNormalized(this);
+ }
+
+ public Quaterniond getUnnormalizedRotation(Quaterniond dest) {
+ return dest.setFromUnnormalized(this);
+ }
+
+ public Quaterniond getNormalizedRotation(Quaterniond dest) {
+ return dest.setFromNormalized(this);
+ }
+
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ return get(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Matrix4x3fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ public float[] get(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy(this, arr, offset);
+ return arr;
+ }
+
+ public float[] get(float[] arr) {
+ return get(arr, 0);
+ }
+
+ public float[] get4x4(float[] arr, int offset) {
+ MemUtil.INSTANCE.copy4x4(this, arr, offset);
+ return arr;
+ }
+
+ public float[] get4x4(float[] arr) {
+ return get4x4(arr, 0);
+ }
+
+ public FloatBuffer get4x4(FloatBuffer buffer) {
+ return get4x4(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get4x4(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get4x4(ByteBuffer buffer) {
+ return get4x4(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get4x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put4x4(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get3x4(FloatBuffer buffer) {
+ return get3x4(buffer.position(), buffer);
+ }
+
+ public FloatBuffer get3x4(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get3x4(ByteBuffer buffer) {
+ return get3x4(buffer.position(), buffer);
+ }
+
+ public ByteBuffer get3x4(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put3x4(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer getTransposed(FloatBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public FloatBuffer getTransposed(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getTransposed(ByteBuffer buffer) {
+ return getTransposed(buffer.position(), buffer);
+ }
+
+ public ByteBuffer getTransposed(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putTransposed(this, index, buffer);
+ return buffer;
+ }
+
+ public float[] getTransposed(float[] arr, int offset) {
+ arr[offset+0] = m00;
+ arr[offset+1] = m10;
+ arr[offset+2] = m20;
+ arr[offset+3] = m30;
+ arr[offset+4] = m01;
+ arr[offset+5] = m11;
+ arr[offset+6] = m21;
+ arr[offset+7] = m31;
+ arr[offset+8] = m02;
+ arr[offset+9] = m12;
+ arr[offset+10] = m22;
+ arr[offset+11] = m32;
+ return arr;
+ }
+
+ public float[] getTransposed(float[] arr) {
+ return getTransposed(arr, 0);
+ }
+
+ /**
+ * Set all the values within this matrix to 0
.
+ *
+ * @return this
+ */
+ public Matrix4x3f zero() {
+ MemUtil.INSTANCE.zero(this);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(float) scale()} instead.
+ *
+ * @see #scale(float)
+ *
+ * @param factor
+ * the scale factor in x, y and z
+ * @return this
+ */
+ public Matrix4x3f scaling(float factor) {
+ return scaling(factor, factor, factor);
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix, use {@link #scale(float, float, float) scale()} instead.
+ *
+ * @see #scale(float, float, float)
+ *
+ * @param x
+ * the scale in x
+ * @param y
+ * the scale in y
+ * @param z
+ * the scale in z
+ * @return this
+ */
+ public Matrix4x3f scaling(float x, float y, float z) {
+ if ((properties & PROPERTY_IDENTITY) == 0)
+ MemUtil.INSTANCE.identity(this);
+ m00 = x;
+ m11 = y;
+ m22 = z;
+ boolean one = Math.absEqualsOne(x) && Math.absEqualsOne(y) && Math.absEqualsOne(z);
+ properties = one ? PROPERTY_ORTHONORMAL : 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a simple scale matrix which scales the base axes by xyz.x
, xyz.y
and xyz.z
respectively.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional scaling.
+ *
+ * In order to post-multiply a scaling transformation directly to a
+ * matrix use {@link #scale(Vector3fc) scale()} instead.
+ *
+ * @see #scale(Vector3fc)
+ *
+ * @param xyz
+ * the scale in x, y and z respectively
+ * @return this
+ */
+ public Matrix4x3f scaling(Vector3fc xyz) {
+ return scaling(xyz.x(), xyz.y(), xyz.z());
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to post-multiply a rotation transformation directly to a
+ * matrix, use {@link #rotate(float, Vector3fc) rotate()} instead.
+ *
+ * @see #rotate(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the axis to rotate about (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3f rotation(float angle, Vector3fc axis) {
+ return rotation(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation using the given {@link AxisAngle4f}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(AxisAngle4f) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3f rotation(AxisAngle4f axisAngle) {
+ return rotation(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this matrix to a rotation matrix which rotates the given radians about a given axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(float, float, float, float) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the rotation axis
+ * @param y
+ * the y-component of the rotation axis
+ * @param z
+ * the z-component of the rotation axis
+ * @return this
+ */
+ public Matrix4x3f rotation(float angle, float x, float y, float z) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotationX(x * angle);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotationY(y * angle);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotationZ(z * angle);
+ return rotationInternal(angle, x, y, z);
+ }
+ private Matrix4x3f rotationInternal(float angle, float x, float y, float z) {
+ float sin = Math.sin(angle);
+ float cos = Math.cosFromSin(sin, angle);
+ float C = 1.0f - cos;
+ float xy = x * y, xz = x * z, yz = y * z;
+ m00 = cos + x * x * C;
+ m01 = xy * C + z * sin;
+ m02 = xz * C - y * sin;
+ m10 = xy * C - z * sin;
+ m11 = cos + y * y * C;
+ m12 = yz * C + x * sin;
+ m20 = xz * C + y * sin;
+ m21 = yz * C - x * sin;
+ m22 = cos + z * z * C;
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3f rotationX(float ang) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = 1.0f;
+ m01 = 0.0f;
+ m02 = 0.0f;
+ m10 = 0.0f;
+ m11 = cos;
+ m12 = sin;
+ m20 = 0.0f;
+ m21 = -sin;
+ m22 = cos;
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3f rotationY(float ang) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = 0.0f;
+ m02 = -sin;
+ m10 = 0.0f;
+ m11 = 1.0f;
+ m12 = 0.0f;
+ m20 = sin;
+ m21 = 0.0f;
+ m22 = cos;
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation transformation about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3f rotationZ(float ang) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ m00 = cos;
+ m01 = sin;
+ m02 = 0.0f;
+ m10 = -sin;
+ m11 = cos;
+ m12 = 0.0f;
+ m20 = 0.0f;
+ m21 = 0.0f;
+ m22 = 1.0f;
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3f rotationXYZ(float angleX, float angleY, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm11 = cosX;
+ float nm12 = sinX;
+ float nm21 = m_sinX;
+ float nm22 = cosX;
+ // rotateY
+ float nm00 = cosY;
+ float nm01 = nm21 * m_sinY;
+ float nm02 = nm22 * m_sinY;
+ m20 = sinY;
+ m21 = nm21 * cosY;
+ m22 = nm22 * cosY;
+ // rotateZ
+ m00 = nm00 * cosZ;
+ m01 = nm01 * cosZ + nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ;
+ m11 = nm01 * m_sinZ + nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // set last column to identity
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4x3f rotationZYX(float angleZ, float angleY, float angleX) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = cosZ;
+ float nm01 = sinZ;
+ float nm10 = m_sinZ;
+ float nm11 = cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY;
+ float nm21 = nm01 * sinY;
+ float nm22 = cosY;
+ m00 = nm00 * cosY;
+ m01 = nm01 * cosY;
+ m02 = m_sinY;
+ // rotateX
+ m10 = nm10 * cosX + nm20 * sinX;
+ m11 = nm11 * cosX + nm21 * sinX;
+ m12 = nm22 * sinX;
+ m20 = nm10 * m_sinX + nm20 * cosX;
+ m21 = nm11 * m_sinX + nm21 * cosX;
+ m22 = nm22 * cosX;
+ // set last column to identity
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3f rotationYXZ(float angleY, float angleX, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm00 = cosY;
+ float nm02 = m_sinY;
+ float nm20 = sinY;
+ float nm22 = cosY;
+ // rotateX
+ float nm10 = nm20 * sinX;
+ float nm11 = cosX;
+ float nm12 = nm22 * sinX;
+ m20 = nm20 * cosX;
+ m21 = m_sinX;
+ m22 = nm22 * cosX;
+ // rotateZ
+ m00 = nm00 * cosZ + nm10 * sinZ;
+ m01 = nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ + nm10 * cosZ;
+ m11 = nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // set last column to identity
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set only the left 3x3 submatrix of this matrix to a rotation of angleX
radians about the X axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3f setRotationXYZ(float angleX, float angleY, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm11 = cosX;
+ float nm12 = sinX;
+ float nm21 = m_sinX;
+ float nm22 = cosX;
+ // rotateY
+ float nm00 = cosY;
+ float nm01 = nm21 * m_sinY;
+ float nm02 = nm22 * m_sinY;
+ m20 = sinY;
+ m21 = nm21 * cosY;
+ m22 = nm22 * cosY;
+ // rotateZ
+ m00 = nm00 * cosZ;
+ m01 = nm01 * cosZ + nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ;
+ m11 = nm01 * m_sinZ + nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set only the left 3x3 submatrix of this matrix to a rotation of angleZ
radians about the Z axis, followed by a rotation
+ * of angleY
radians about the Y axis and followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4x3f setRotationZYX(float angleZ, float angleY, float angleX) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = cosZ;
+ float nm01 = sinZ;
+ float nm10 = m_sinZ;
+ float nm11 = cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY;
+ float nm21 = nm01 * sinY;
+ float nm22 = cosY;
+ m00 = nm00 * cosY;
+ m01 = nm01 * cosY;
+ m02 = m_sinY;
+ // rotateX
+ m10 = nm10 * cosX + nm20 * sinX;
+ m11 = nm11 * cosX + nm21 * sinX;
+ m12 = nm22 * sinX;
+ m20 = nm10 * m_sinX + nm20 * cosX;
+ m21 = nm11 * m_sinX + nm21 * cosX;
+ m22 = nm22 * cosX;
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set only the left 3x3 submatrix of this matrix to a rotation of angleY
radians about the Y axis, followed by a rotation
+ * of angleX
radians about the X axis and followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3f setRotationYXZ(float angleY, float angleX, float angleZ) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm00 = cosY;
+ float nm02 = m_sinY;
+ float nm20 = sinY;
+ float nm22 = cosY;
+ // rotateX
+ float nm10 = nm20 * sinX;
+ float nm11 = cosX;
+ float nm12 = nm22 * sinX;
+ m20 = nm20 * cosX;
+ m21 = m_sinX;
+ m22 = nm22 * cosX;
+ // rotateZ
+ m00 = nm00 * cosZ + nm10 * sinZ;
+ m01 = nm11 * sinZ;
+ m02 = nm02 * cosZ + nm12 * sinZ;
+ m10 = nm00 * m_sinZ + nm10 * cosZ;
+ m11 = nm11 * cosZ;
+ m12 = nm02 * m_sinZ + nm12 * cosZ;
+ properties &= ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return this;
+ }
+
+ /**
+ * Set this matrix to the rotation - and possibly scaling - transformation of the given {@link Quaternionfc}.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * The resulting matrix can be multiplied against another transformation
+ * matrix to obtain an additional rotation.
+ *
+ * In order to apply the rotation transformation to an existing transformation,
+ * use {@link #rotate(Quaternionfc) rotate()} instead.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3f rotation(Quaternionfc quat) {
+ float w2 = quat.w() * quat.w();
+ float x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y();
+ float z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw;
+ float xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz;
+ float yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz;
+ float xw = quat.x() * quat.w(), dxw = xw + xw;
+ _m00(w2 + x2 - z2 - y2);
+ _m01(dxy + dzw);
+ _m02(dxz - dyw);
+ _m10(dxy - dzw);
+ _m11(y2 - z2 + w2 - x2);
+ _m12(dyz + dxw);
+ _m20(dyw + dxz);
+ _m21(dyz - dxw);
+ _m22(z2 - y2 - x2 + w2);
+ _m30(0.0f);
+ _m31(0.0f);
+ _m32(0.0f);
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, and S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(float, float, float)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @return this
+ */
+ public Matrix4x3f translationRotateScale(float tx, float ty, float tz,
+ float qx, float qy, float qz, float qw,
+ float sx, float sy, float sz) {
+ float dqx = qx + qx;
+ float dqy = qy + qy;
+ float dqz = qz + qz;
+ float q00 = dqx * qx;
+ float q11 = dqy * qy;
+ float q22 = dqz * qz;
+ float q01 = dqx * qy;
+ float q02 = dqx * qz;
+ float q03 = dqx * qw;
+ float q12 = dqy * qz;
+ float q13 = dqy * qw;
+ float q23 = dqz * qw;
+ m00 = sx - (q11 + q22) * sx;
+ m01 = (q01 + q23) * sx;
+ m02 = (q02 - q13) * sx;
+ m10 = (q01 - q23) * sy;
+ m11 = sy - (q22 + q00) * sy;
+ m12 = (q12 + q03) * sy;
+ m20 = (q02 + q13) * sz;
+ m21 = (q12 - q03) * sz;
+ m22 = sz - (q11 + q00) * sz;
+ m30 = tx;
+ m31 = ty;
+ m32 = tz;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, and S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the scaling transformation will be applied first, then the rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @return this
+ */
+ public Matrix4x3f translationRotateScale(Vector3fc translation,
+ Quaternionfc quat,
+ Vector3fc scale) {
+ return translationRotateScale(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z());
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation transformation specified by the quaternion (qx, qy, qz, qw)
, S
is a scaling transformation
+ * which scales the three axes x, y and z by (sx, sy, sz)
.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).scale(sx, sy, sz).mul(m)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #scale(float, float, float)
+ * @see #mul(Matrix4x3fc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param sx
+ * the scaling factor for the x-axis
+ * @param sy
+ * the scaling factor for the y-axis
+ * @param sz
+ * the scaling factor for the z-axis
+ * @param m
+ * the matrix to multiply by
+ * @return this
+ */
+ public Matrix4x3f translationRotateScaleMul(float tx, float ty, float tz,
+ float qx, float qy, float qz, float qw,
+ float sx, float sy, float sz,
+ Matrix4x3f m) {
+ float dqx = qx + qx;
+ float dqy = qy + qy;
+ float dqz = qz + qz;
+ float q00 = dqx * qx;
+ float q11 = dqy * qy;
+ float q22 = dqz * qz;
+ float q01 = dqx * qy;
+ float q02 = dqx * qz;
+ float q03 = dqx * qw;
+ float q12 = dqy * qz;
+ float q13 = dqy * qw;
+ float q23 = dqz * qw;
+ float nm00 = sx - (q11 + q22) * sx;
+ float nm01 = (q01 + q23) * sx;
+ float nm02 = (q02 - q13) * sx;
+ float nm10 = (q01 - q23) * sy;
+ float nm11 = sy - (q22 + q00) * sy;
+ float nm12 = (q12 + q03) * sy;
+ float nm20 = (q02 + q13) * sz;
+ float nm21 = (q12 - q03) * sz;
+ float nm22 = sz - (q11 + q00) * sz;
+ float m00 = nm00 * m.m00 + nm10 * m.m01 + nm20 * m.m02;
+ float m01 = nm01 * m.m00 + nm11 * m.m01 + nm21 * m.m02;
+ m02 = nm02 * m.m00 + nm12 * m.m01 + nm22 * m.m02;
+ this.m00 = m00;
+ this.m01 = m01;
+ float m10 = nm00 * m.m10 + nm10 * m.m11 + nm20 * m.m12;
+ float m11 = nm01 * m.m10 + nm11 * m.m11 + nm21 * m.m12;
+ m12 = nm02 * m.m10 + nm12 * m.m11 + nm22 * m.m12;
+ this.m10 = m10;
+ this.m11 = m11;
+ float m20 = nm00 * m.m20 + nm10 * m.m21 + nm20 * m.m22;
+ float m21 = nm01 * m.m20 + nm11 * m.m21 + nm21 * m.m22;
+ m22 = nm02 * m.m20 + nm12 * m.m21 + nm22 * m.m22;
+ this.m20 = m20;
+ this.m21 = m21;
+ float m30 = nm00 * m.m30 + nm10 * m.m31 + nm20 * m.m32 + tx;
+ float m31 = nm01 * m.m30 + nm11 * m.m31 + nm21 * m.m32 + ty;
+ m32 = nm02 * m.m30 + nm12 * m.m31 + nm22 * m.m32 + tz;
+ this.m30 = m30;
+ this.m31 = m31;
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * S * M
, where T
is the given translation
,
+ * R
is a rotation transformation specified by the given quaternion, S
is a scaling transformation
+ * which scales the axes by scale
.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(translation).rotate(quat).scale(scale).mul(m)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param translation
+ * the translation
+ * @param quat
+ * the quaternion representing a rotation
+ * @param scale
+ * the scaling factors
+ * @param m
+ * the matrix to multiply by
+ * @return this
+ */
+ public Matrix4x3f translationRotateScaleMul(Vector3fc translation, Quaternionfc quat, Vector3fc scale, Matrix4x3f m) {
+ return translationRotateScaleMul(translation.x(), translation.y(), translation.z(), quat.x(), quat.y(), quat.z(), quat.w(), scale.x(), scale.y(), scale.z(), m);
+ }
+
+ /**
+ * Set this
matrix to T * R
, where T
is a translation by the given (tx, ty, tz)
and
+ * R
is a rotation transformation specified by the given quaternion.
+ *
+ * When transforming a vector by the resulting matrix the rotation transformation will be applied first and then the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param quat
+ * the quaternion representing a rotation
+ * @return this
+ */
+ public Matrix4x3f translationRotate(float tx, float ty, float tz, Quaternionfc quat) {
+ float dqx = quat.x() + quat.x();
+ float dqy = quat.y() + quat.y();
+ float dqz = quat.z() + quat.z();
+ float q00 = dqx * quat.x();
+ float q11 = dqy * quat.y();
+ float q22 = dqz * quat.z();
+ float q01 = dqx * quat.y();
+ float q02 = dqx * quat.z();
+ float q03 = dqx * quat.w();
+ float q12 = dqy * quat.z();
+ float q13 = dqy * quat.w();
+ float q23 = dqz * quat.w();
+ m00 = 1.0f - (q11 + q22);
+ m01 = q01 + q23;
+ m02 = q02 - q13;
+ m10 = q01 - q23;
+ m11 = 1.0f - (q22 + q00);
+ m12 = q12 + q03;
+ m20 = q02 + q13;
+ m21 = q12 - q03;
+ m22 = 1.0f - (q11 + q00);
+ m30 = tx;
+ m31 = ty;
+ m32 = tz;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this
matrix to T * R * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation - and possibly scaling - transformation specified by the given quaternion and M
is the given matrix mat
.
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).mul(mat)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #mul(Matrix4x3fc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param quat
+ * the quaternion representing a rotation
+ * @param mat
+ * the matrix to multiply with
+ * @return this
+ */
+ public Matrix4x3f translationRotateMul(float tx, float ty, float tz, Quaternionfc quat, Matrix4x3fc mat) {
+ return translationRotateMul(tx, ty, tz, quat.x(), quat.y(), quat.z(), quat.w(), mat);
+ }
+
+ /**
+ * Set this
matrix to T * R * M
, where T
is a translation by the given (tx, ty, tz)
,
+ * R
is a rotation - and possibly scaling - transformation specified by the quaternion (qx, qy, qz, qw)
and M
is the given matrix mat
+ *
+ * When transforming a vector by the resulting matrix the transformation described by M
will be applied first, then the scaling, then rotation and
+ * at last the translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(tx, ty, tz).rotate(quat).mul(mat)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotate(Quaternionfc)
+ * @see #mul(Matrix4x3fc)
+ *
+ * @param tx
+ * the number of units by which to translate the x-component
+ * @param ty
+ * the number of units by which to translate the y-component
+ * @param tz
+ * the number of units by which to translate the z-component
+ * @param qx
+ * the x-coordinate of the vector part of the quaternion
+ * @param qy
+ * the y-coordinate of the vector part of the quaternion
+ * @param qz
+ * the z-coordinate of the vector part of the quaternion
+ * @param qw
+ * the scalar part of the quaternion
+ * @param mat
+ * the matrix to multiply with
+ * @return this
+ */
+ public Matrix4x3f translationRotateMul(float tx, float ty, float tz, float qx, float qy, float qz, float qw, Matrix4x3fc mat) {
+ float w2 = qw * qw;
+ float x2 = qx * qx;
+ float y2 = qy * qy;
+ float z2 = qz * qz;
+ float zw = qz * qw;
+ float xy = qx * qy;
+ float xz = qx * qz;
+ float yw = qy * qw;
+ float yz = qy * qz;
+ float xw = qx * qw;
+ float nm00 = w2 + x2 - z2 - y2;
+ float nm01 = xy + zw + zw + xy;
+ float nm02 = xz - yw + xz - yw;
+ float nm10 = -zw + xy - zw + xy;
+ float nm11 = y2 - z2 + w2 - x2;
+ float nm12 = yz + yz + xw + xw;
+ float nm20 = yw + xz + xz + yw;
+ float nm21 = yz + yz - xw - xw;
+ float nm22 = z2 - y2 - x2 + w2;
+ m00 = nm00 * mat.m00() + nm10 * mat.m01() + nm20 * mat.m02();
+ m01 = nm01 * mat.m00() + nm11 * mat.m01() + nm21 * mat.m02();
+ m02 = nm02 * mat.m00() + nm12 * mat.m01() + nm22 * mat.m02();
+ m10 = nm00 * mat.m10() + nm10 * mat.m11() + nm20 * mat.m12();
+ m11 = nm01 * mat.m10() + nm11 * mat.m11() + nm21 * mat.m12();
+ m12 = nm02 * mat.m10() + nm12 * mat.m11() + nm22 * mat.m12();
+ m20 = nm00 * mat.m20() + nm10 * mat.m21() + nm20 * mat.m22();
+ m21 = nm01 * mat.m20() + nm11 * mat.m21() + nm21 * mat.m22();
+ m22 = nm02 * mat.m20() + nm12 * mat.m21() + nm22 * mat.m22();
+ m30 = nm00 * mat.m30() + nm10 * mat.m31() + nm20 * mat.m32() + tx;
+ m31 = nm01 * mat.m30() + nm11 * mat.m31() + nm21 * mat.m32() + ty;
+ m32 = nm02 * mat.m30() + nm12 * mat.m31() + nm22 * mat.m32() + tz;
+ this.properties = 0;
+ return this;
+ }
+
+ /**
+ * Set the left 3x3 submatrix of this {@link Matrix4x3f} to the given {@link Matrix3fc} and don't change the other elements.
+ *
+ * @param mat
+ * the 3x3 matrix
+ * @return this
+ */
+ public Matrix4x3f set3x3(Matrix3fc mat) {
+ if (mat instanceof Matrix3f) {
+ MemUtil.INSTANCE.copy3x3((Matrix3f) mat, this);
+ } else {
+ set3x3Matrix3fc(mat);
+ }
+ properties = 0;
+ return this;
+ }
+ private void set3x3Matrix3fc(Matrix3fc mat) {
+ m00 = mat.m00();
+ m01 = mat.m01();
+ m02 = mat.m02();
+ m10 = mat.m10();
+ m11 = mat.m11();
+ m12 = mat.m12();
+ m20 = mat.m20();
+ m21 = mat.m21();
+ m22 = mat.m22();
+ }
+
+ public Vector4f transform(Vector4f v) {
+ return v.mul(this);
+ }
+
+ public Vector4f transform(Vector4fc v, Vector4f dest) {
+ return v.mul(this, dest);
+ }
+
+ public Vector3f transformPosition(Vector3f v) {
+ v.set(m00 * v.x + m10 * v.y + m20 * v.z + m30,
+ m01 * v.x + m11 * v.y + m21 * v.z + m31,
+ m02 * v.x + m12 * v.y + m22 * v.z + m32);
+ return v;
+ }
+
+ public Vector3f transformPosition(Vector3fc v, Vector3f dest) {
+ dest.set(m00 * v.x() + m10 * v.y() + m20 * v.z() + m30,
+ m01 * v.x() + m11 * v.y() + m21 * v.z() + m31,
+ m02 * v.x() + m12 * v.y() + m22 * v.z() + m32);
+ return dest;
+ }
+
+ public Vector3f transformDirection(Vector3f v) {
+ v.set(m00 * v.x + m10 * v.y + m20 * v.z,
+ m01 * v.x + m11 * v.y + m21 * v.z,
+ m02 * v.x + m12 * v.y + m22 * v.z);
+ return v;
+ }
+
+ public Vector3f transformDirection(Vector3fc v, Vector3f dest) {
+ dest.set(m00 * v.x() + m10 * v.y() + m20 * v.z(),
+ m01 * v.x() + m11 * v.y() + m21 * v.z(),
+ m02 * v.x() + m12 * v.y() + m22 * v.z());
+ return dest;
+ }
+
+ public Matrix4x3f scale(Vector3fc xyz, Matrix4x3f dest) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @return this
+ */
+ public Matrix4x3f scale(Vector3fc xyz) {
+ return scale(xyz.x(), xyz.y(), xyz.z(), this);
+ }
+
+ public Matrix4x3f scale(float xyz, Matrix4x3f dest) {
+ return scale(xyz, xyz, xyz, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * Individual scaling of all three axes can be applied using {@link #scale(float, float, float)}.
+ *
+ * @see #scale(float, float, float)
+ *
+ * @param xyz
+ * the factor for all components
+ * @return this
+ */
+ public Matrix4x3f scale(float xyz) {
+ return scale(xyz, xyz, xyz);
+ }
+
+ public Matrix4x3f scaleXY(float x, float y, Matrix4x3f dest) {
+ return scale(x, y, 1.0f, dest);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the X axis by x
and the Y axis by y
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @return this
+ */
+ public Matrix4x3f scaleXY(float x, float y) {
+ return scale(x, y, 1.0f);
+ }
+
+ public Matrix4x3f scale(float x, float y, float z, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ return scaleGeneric(x, y, z, dest);
+ }
+ private Matrix4x3f scaleGeneric(float x, float y, float z, Matrix4x3f dest) {
+ dest.m00 = m00 * x;
+ dest.m01 = m01 * x;
+ dest.m02 = m02 * x;
+ dest.m10 = m10 * y;
+ dest.m11 = m11 * y;
+ dest.m12 = m12 * y;
+ dest.m20 = m20 * z;
+ dest.m21 = m21 * z;
+ dest.m22 = m22 * z;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4x3f scale(float x, float y, float z) {
+ return scale(x, y, z, this);
+ }
+
+ public Matrix4x3f scaleLocal(float x, float y, float z, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.scaling(x, y, z);
+ float nm00 = x * m00;
+ float nm01 = y * m01;
+ float nm02 = z * m02;
+ float nm10 = x * m10;
+ float nm11 = y * m11;
+ float nm12 = z * m12;
+ float nm20 = x * m20;
+ float nm21 = y * m21;
+ float nm22 = z * m22;
+ float nm30 = x * m30;
+ float nm31 = y * m31;
+ float nm32 = z * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+ return dest;
+ }
+
+ public Matrix4x3f scaleAround(float sx, float sy, float sz, float ox, float oy, float oz, Matrix4x3f dest) {
+ float nm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ float nm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ float nm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ boolean one = Math.absEqualsOne(sx) && Math.absEqualsOne(sy) && Math.absEqualsOne(sz);
+ return dest
+ ._m00(m00 * sx)
+ ._m01(m01 * sx)
+ ._m02(m02 * sx)
+ ._m10(m10 * sy)
+ ._m11(m11 * sy)
+ ._m12(m12 * sy)
+ ._m20(m20 * sz)
+ ._m21(m21 * sz)
+ ._m22(m22 * sz)
+ ._m30(-dest.m00 * ox - dest.m10 * oy - dest.m20 * oz + nm30)
+ ._m31(-dest.m01 * ox - dest.m11 * oy - dest.m21 * oz + nm31)
+ ._m32(-dest.m02 * ox - dest.m12 * oy - dest.m22 * oz + nm32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | (one ? 0 : PROPERTY_ORTHONORMAL)));
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4x3f scaleAround(float sx, float sy, float sz, float ox, float oy, float oz) {
+ return scaleAround(sx, sy, sz, ox, oy, oz, this);
+ }
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @return this
+ */
+ public Matrix4x3f scaleAround(float factor, float ox, float oy, float oz) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, this);
+ }
+
+ public Matrix4x3f scaleAround(float factor, float ox, float oy, float oz, Matrix4x3f dest) {
+ return scaleAround(factor, factor, factor, ox, oy, oz, dest);
+ }
+
+ /**
+ * Pre-multiply scaling to this matrix by scaling the base axes by the given x,
+ * y and z factors.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
, the
+ * scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @return this
+ */
+ public Matrix4x3f scaleLocal(float x, float y, float z) {
+ return scaleLocal(x, y, z, this);
+ }
+
+ public Matrix4x3f rotateX(float ang, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationX(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float x = m30, y = m31, z = m32;
+ return dest.rotationX(ang).setTranslation(x, y, z);
+ }
+ return rotateXInternal(ang, dest);
+ }
+ private Matrix4x3f rotateXInternal(float ang, Matrix4x3f dest) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ float rm11 = cos;
+ float rm12 = sin;
+ float rm21 = -sin;
+ float rm22 = cos;
+
+ // add temporaries for dependent values
+ float nm10 = m10 * rm11 + m20 * rm12;
+ float nm11 = m11 * rm11 + m21 * rm12;
+ float nm12 = m12 * rm11 + m22 * rm12;
+ // set non-dependent values directly
+ dest.m20 = m10 * rm21 + m20 * rm22;
+ dest.m21 = m11 * rm21 + m21 * rm22;
+ dest.m22 = m12 * rm21 + m22 * rm22;
+ // set other values
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3f rotateX(float ang) {
+ return rotateX(ang, this);
+ }
+
+ public Matrix4x3f rotateY(float ang, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationY(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float x = m30, y = m31, z = m32;
+ return dest.rotationY(ang).setTranslation(x, y, z);
+ }
+ return rotateYInternal(ang, dest);
+ }
+ private Matrix4x3f rotateYInternal(float ang, Matrix4x3f dest) {
+ float cos, sin;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ float rm00 = cos;
+ float rm02 = -sin;
+ float rm20 = sin;
+ float rm22 = cos;
+
+ // add temporaries for dependent values
+ float nm00 = m00 * rm00 + m20 * rm02;
+ float nm01 = m01 * rm00 + m21 * rm02;
+ float nm02 = m02 * rm00 + m22 * rm02;
+ // set non-dependent values directly
+ dest.m20 = m00 * rm20 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m22 * rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3f rotateY(float ang) {
+ return rotateY(ang, this);
+ }
+
+ public Matrix4x3f rotateZ(float ang, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZ(ang);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float x = m30, y = m31, z = m32;
+ return dest.rotationZ(ang).setTranslation(x, y, z);
+ }
+ return rotateZInternal(ang, dest);
+ }
+ private Matrix4x3f rotateZInternal(float ang, Matrix4x3f dest) {
+ float sin, cos;
+ sin = Math.sin(ang);
+ cos = Math.cosFromSin(sin, ang);
+ float rm00 = cos;
+ float rm01 = sin;
+ float rm10 = -sin;
+ float rm11 = cos;
+
+ // add temporaries for dependent values
+ float nm00 = m00 * rm00 + m10 * rm01;
+ float nm01 = m01 * rm00 + m11 * rm01;
+ float nm02 = m02 * rm00 + m12 * rm01;
+ // set non-dependent values directly
+ dest.m10 = m00 * rm10 + m10 * rm11;
+ dest.m11 = m01 * rm10 + m11 * rm11;
+ dest.m12 = m02 * rm10 + m12 * rm11;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @return this
+ */
+ public Matrix4x3f rotateZ(float ang) {
+ return rotateZ(ang, this);
+ }
+
+ /**
+ * Apply rotation of angles.x
radians about the X axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angles.x).rotateY(angles.y).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4x3f rotateXYZ(Vector3f angles) {
+ return rotateXYZ(angles.x, angles.y, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3f rotateXYZ(float angleX, float angleY, float angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Matrix4x3f rotateXYZ(float angleX, float angleY, float angleZ, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationXYZ(angleX, angleY, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationXYZ(angleX, angleY, angleZ).setTranslation(tx, ty, tz);
+ }
+ return rotateXYZInternal(angleX, angleY, angleZ, dest);
+ }
+ private Matrix4x3f rotateXYZInternal(float angleX, float angleY, float angleZ, Matrix4x3f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinX = -sinX;
+ float m_sinY = -sinY;
+ float m_sinZ = -sinZ;
+
+ // rotateX
+ float nm10 = m10 * cosX + m20 * sinX;
+ float nm11 = m11 * cosX + m21 * sinX;
+ float nm12 = m12 * cosX + m22 * sinX;
+ float nm20 = m10 * m_sinX + m20 * cosX;
+ float nm21 = m11 * m_sinX + m21 * cosX;
+ float nm22 = m12 * m_sinX + m22 * cosX;
+ // rotateY
+ float nm00 = m00 * cosY + nm20 * m_sinY;
+ float nm01 = m01 * cosY + nm21 * m_sinY;
+ float nm02 = m02 * cosY + nm22 * m_sinY;
+ dest.m20 = m00 * sinY + nm20 * cosY;
+ dest.m21 = m01 * sinY + nm21 * cosY;
+ dest.m22 = m02 * sinY + nm22 * cosY;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // copy last column from 'this'
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.z
radians about the Z axis, followed by a rotation of angles.y
radians about the Y axis and
+ * followed by a rotation of angles.x
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angles.z).rotateY(angles.y).rotateX(angles.x)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4x3f rotateZYX(Vector3f angles) {
+ return rotateZYX(angles.z, angles.y, angles.x);
+ }
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @return this
+ */
+ public Matrix4x3f rotateZYX(float angleZ, float angleY, float angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Matrix4x3f rotateZYX(float angleZ, float angleY, float angleX, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationZYX(angleZ, angleY, angleX);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationZYX(angleZ, angleY, angleX).setTranslation(tx, ty, tz);
+ }
+ return rotateZYXInternal(angleZ, angleY, angleX, dest);
+ }
+ private Matrix4x3f rotateZYXInternal(float angleZ, float angleY, float angleX, Matrix4x3f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinZ = -sinZ;
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+
+ // rotateZ
+ float nm00 = m00 * cosZ + m10 * sinZ;
+ float nm01 = m01 * cosZ + m11 * sinZ;
+ float nm02 = m02 * cosZ + m12 * sinZ;
+ float nm10 = m00 * m_sinZ + m10 * cosZ;
+ float nm11 = m01 * m_sinZ + m11 * cosZ;
+ float nm12 = m02 * m_sinZ + m12 * cosZ;
+ // rotateY
+ float nm20 = nm00 * sinY + m20 * cosY;
+ float nm21 = nm01 * sinY + m21 * cosY;
+ float nm22 = nm02 * sinY + m22 * cosY;
+ dest.m00 = nm00 * cosY + m20 * m_sinY;
+ dest.m01 = nm01 * cosY + m21 * m_sinY;
+ dest.m02 = nm02 * cosY + m22 * m_sinY;
+ // rotateX
+ dest.m10 = nm10 * cosX + nm20 * sinX;
+ dest.m11 = nm11 * cosX + nm21 * sinX;
+ dest.m12 = nm12 * cosX + nm22 * sinX;
+ dest.m20 = nm10 * m_sinX + nm20 * cosX;
+ dest.m21 = nm11 * m_sinX + nm21 * cosX;
+ dest.m22 = nm12 * m_sinX + nm22 * cosX;
+ // copy last column from 'this'
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation of angles.y
radians about the Y axis, followed by a rotation of angles.x
radians about the X axis and
+ * followed by a rotation of angles.z
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angles.y).rotateX(angles.x).rotateZ(angles.z)
+ *
+ * @param angles
+ * the Euler angles
+ * @return this
+ */
+ public Matrix4x3f rotateYXZ(Vector3f angles) {
+ return rotateYXZ(angles.y, angles.x, angles.z);
+ }
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @return this
+ */
+ public Matrix4x3f rotateYXZ(float angleY, float angleX, float angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Matrix4x3f rotateYXZ(float angleY, float angleX, float angleZ, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotationYXZ(angleY, angleX, angleZ);
+ else if ((properties & PROPERTY_TRANSLATION) != 0) {
+ float tx = m30, ty = m31, tz = m32;
+ return dest.rotationYXZ(angleY, angleX, angleZ).setTranslation(tx, ty, tz);
+ }
+ return rotateYXZInternal(angleY, angleX, angleZ, dest);
+ }
+ private Matrix4x3f rotateYXZInternal(float angleY, float angleX, float angleZ, Matrix4x3f dest) {
+ float sinX = Math.sin(angleX);
+ float cosX = Math.cosFromSin(sinX, angleX);
+ float sinY = Math.sin(angleY);
+ float cosY = Math.cosFromSin(sinY, angleY);
+ float sinZ = Math.sin(angleZ);
+ float cosZ = Math.cosFromSin(sinZ, angleZ);
+ float m_sinY = -sinY;
+ float m_sinX = -sinX;
+ float m_sinZ = -sinZ;
+
+ // rotateY
+ float nm20 = m00 * sinY + m20 * cosY;
+ float nm21 = m01 * sinY + m21 * cosY;
+ float nm22 = m02 * sinY + m22 * cosY;
+ float nm00 = m00 * cosY + m20 * m_sinY;
+ float nm01 = m01 * cosY + m21 * m_sinY;
+ float nm02 = m02 * cosY + m22 * m_sinY;
+ // rotateX
+ float nm10 = m10 * cosX + nm20 * sinX;
+ float nm11 = m11 * cosX + nm21 * sinX;
+ float nm12 = m12 * cosX + nm22 * sinX;
+ dest.m20 = m10 * m_sinX + nm20 * cosX;
+ dest.m21 = m11 * m_sinX + nm21 * cosX;
+ dest.m22 = m12 * m_sinX + nm22 * cosX;
+ // rotateZ
+ dest.m00 = nm00 * cosZ + nm10 * sinZ;
+ dest.m01 = nm01 * cosZ + nm11 * sinZ;
+ dest.m02 = nm02 * cosZ + nm12 * sinZ;
+ dest.m10 = nm00 * m_sinZ + nm10 * cosZ;
+ dest.m11 = nm01 * m_sinZ + nm11 * cosZ;
+ dest.m12 = nm02 * m_sinZ + nm12 * cosZ;
+ // copy last column from 'this'
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotate(float ang, float x, float y, float z, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(ang, x, y, z);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(ang, x, y, z, dest);
+ return rotateGeneric(ang, x, y, z, dest);
+ }
+ private Matrix4x3f rotateGeneric(float ang, float x, float y, float z, Matrix4x3f dest) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateX(x * ang, dest);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateY(y * ang, dest);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateZ(z * ang, dest);
+ return rotateGenericInternal(ang, x, y, z, dest);
+ }
+ private Matrix4x3f rotateGenericInternal(float ang, float x, float y, float z, Matrix4x3f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float rm00 = xx * C + c;
+ float rm01 = xy * C + z * s;
+ float rm02 = xz * C - y * s;
+ float rm10 = xy * C - z * s;
+ float rm11 = yy * C + c;
+ float rm12 = yz * C + x * s;
+ float rm20 = xz * C + y * s;
+ float rm21 = yz * C - x * s;
+ float rm22 = zz * C + c;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4x3f rotate(float ang, float x, float y, float z) {
+ return rotate(ang, x, y, z, this);
+ }
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation matrix without post-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateTranslation(float ang, float x, float y, float z, Matrix4x3f dest) {
+ float tx = m30, ty = m31, tz = m32;
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return dest.rotationX(x * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return dest.rotationY(y * ang).setTranslation(tx, ty, tz);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return dest.rotationZ(z * ang).setTranslation(tx, ty, tz);
+ return rotateTranslationInternal(ang, x, y, z, dest);
+ }
+ private Matrix4x3f rotateTranslationInternal(float ang, float x, float y, float z, Matrix4x3f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float rm00 = xx * C + c;
+ float rm01 = xy * C + z * s;
+ float rm02 = xz * C - y * s;
+ float rm10 = xy * C - z * s;
+ float rm11 = yy * C + c;
+ float rm12 = yz * C + x * s;
+ float rm20 = xz * C + y * s;
+ float rm21 = yz * C - x * s;
+ float rm22 = zz * C + c;
+ float nm00 = rm00;
+ float nm01 = rm01;
+ float nm02 = rm02;
+ float nm10 = rm10;
+ float nm11 = rm11;
+ float nm12 = rm12;
+ // set non-dependent values directly
+ dest.m20 = rm20;
+ dest.m21 = rm21;
+ dest.m22 = rm22;
+ // set other values
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply the rotation transformation of the given {@link Quaternionfc} to this matrix while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4x3f rotateAround(Quaternionfc quat, float ox, float oy, float oz) {
+ return rotateAround(quat, ox, oy, oz, this);
+ }
+
+ private Matrix4x3f rotateAroundAffine(Quaternionfc quat, float ox, float oy, float oz, Matrix4x3f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = dxy - dzw;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float tm30 = m00 * ox + m10 * oy + m20 * oz + m30;
+ float tm31 = m01 * ox + m11 * oy + m21 * oz + m31;
+ float tm32 = m02 * ox + m12 * oy + m22 * oz + m32;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest
+ ._m20(m00 * rm20 + m10 * rm21 + m20 * rm22)
+ ._m21(m01 * rm20 + m11 * rm21 + m21 * rm22)
+ ._m22(m02 * rm20 + m12 * rm21 + m22 * rm22)
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m30(-nm00 * ox - nm10 * oy - m20 * oz + tm30)
+ ._m31(-nm01 * ox - nm11 * oy - m21 * oz + tm31)
+ ._m32(-nm02 * ox - nm12 * oy - m22 * oz + tm32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ public Matrix4x3f rotateAround(Quaternionfc quat, float ox, float oy, float oz, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return rotationAround(quat, ox, oy, oz);
+ return rotateAroundAffine(quat, ox, oy, oz, dest);
+ }
+
+ /**
+ * Set this matrix to a transformation composed of a rotation of the specified {@link Quaternionfc} while using (ox, oy, oz)
as the rotation origin.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * This method is equivalent to calling: translation(ox, oy, oz).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @return this
+ */
+ public Matrix4x3f rotationAround(Quaternionfc quat, float ox, float oy, float oz) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ this._m20(dyw + dxz);
+ this._m21(dyz - dxw);
+ this._m22(z2 - y2 - x2 + w2);
+ this._m00(w2 + x2 - z2 - y2);
+ this._m01(dxy + dzw);
+ this._m02(dxz - dyw);
+ this._m10(dxy - dzw);
+ this._m11(y2 - z2 + w2 - x2);
+ this._m12(dyz + dxw);
+ this._m30(-m00 * ox - m10 * oy - m20 * oz + ox);
+ this._m31(-m01 * ox - m11 * oy - m21 * oz + oy);
+ this._m32(-m02 * ox - m12 * oy - m22 * oz + oz);
+ this.properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateLocal(float ang, float x, float y, float z, Matrix4x3f dest) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateLocalX(x * ang, dest);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateLocalY(y * ang, dest);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateLocalZ(z * ang, dest);
+ return rotateLocalInternal(ang, x, y, z, dest);
+ }
+ private Matrix4x3f rotateLocalInternal(float ang, float x, float y, float z, Matrix4x3f dest) {
+ float s = Math.sin(ang);
+ float c = Math.cosFromSin(s, ang);
+ float C = 1.0f - c;
+ float xx = x * x, xy = x * y, xz = x * z;
+ float yy = y * y, yz = y * z;
+ float zz = z * z;
+ float lm00 = xx * C + c;
+ float lm01 = xy * C + z * s;
+ float lm02 = xz * C - y * s;
+ float lm10 = xy * C - z * s;
+ float lm11 = yy * C + c;
+ float lm12 = yz * C + x * s;
+ float lm20 = xz * C + y * s;
+ float lm21 = yz * C - x * s;
+ float lm22 = zz * C + c;
+ float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ float nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ float nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ float nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotation(float, float, float, float) rotation()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(float, float, float, float)
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @return this
+ */
+ public Matrix4x3f rotateLocal(float ang, float x, float y, float z) {
+ return rotateLocal(ang, x, y, z, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the X axis to this matrix by rotating the given amount of radians
+ * about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(float) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateLocalX(float ang, Matrix4x3f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm01 = cos * m01 - sin * m02;
+ float nm02 = sin * m01 + cos * m02;
+ float nm11 = cos * m11 - sin * m12;
+ float nm12 = sin * m11 + cos * m12;
+ float nm21 = cos * m21 - sin * m22;
+ float nm22 = sin * m21 + cos * m22;
+ float nm31 = cos * m31 - sin * m32;
+ float nm32 = sin * m31 + cos * m32;
+ dest
+ ._m00(m00)
+ ._m01(nm01)
+ ._m02(nm02)
+ ._m10(m10)
+ ._m11(nm11)
+ ._m12(nm12)
+ ._m20(m20)
+ ._m21(nm21)
+ ._m22(nm22)
+ ._m30(m30)
+ ._m31(nm31)
+ ._m32(nm32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the X axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationX(float) rotationX()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationX(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the X axis
+ * @return this
+ */
+ public Matrix4x3f rotateLocalX(float ang) {
+ return rotateLocalX(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Y axis to this matrix by rotating the given amount of radians
+ * about the Y axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateLocalY(float ang, Matrix4x3f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm00 = cos * m00 + sin * m02;
+ float nm02 = -sin * m00 + cos * m02;
+ float nm10 = cos * m10 + sin * m12;
+ float nm12 = -sin * m10 + cos * m12;
+ float nm20 = cos * m20 + sin * m22;
+ float nm22 = -sin * m20 + cos * m22;
+ float nm30 = cos * m30 + sin * m32;
+ float nm32 = -sin * m30 + cos * m32;
+ dest
+ ._m00(nm00)
+ ._m01(m01)
+ ._m02(nm02)
+ ._m10(nm10)
+ ._m11(m11)
+ ._m12(nm12)
+ ._m20(nm20)
+ ._m21(m21)
+ ._m22(nm22)
+ ._m30(nm30)
+ ._m31(m31)
+ ._m32(nm32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Y axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationY(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Y axis
+ * @return this
+ */
+ public Matrix4x3f rotateLocalY(float ang) {
+ return rotateLocalY(ang, this);
+ }
+
+ /**
+ * Pre-multiply a rotation around the Z axis to this matrix by rotating the given amount of radians
+ * about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(float) rotationZ()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationZ(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateLocalZ(float ang, Matrix4x3f dest) {
+ float sin = Math.sin(ang);
+ float cos = Math.cosFromSin(sin, ang);
+ float nm00 = cos * m00 - sin * m01;
+ float nm01 = sin * m00 + cos * m01;
+ float nm10 = cos * m10 - sin * m11;
+ float nm11 = sin * m10 + cos * m11;
+ float nm20 = cos * m20 - sin * m21;
+ float nm21 = sin * m20 + cos * m21;
+ float nm30 = cos * m30 - sin * m31;
+ float nm31 = sin * m30 + cos * m31;
+ dest
+ ._m00(nm00)
+ ._m01(nm01)
+ ._m02(m02)
+ ._m10(nm10)
+ ._m11(nm11)
+ ._m12(m12)
+ ._m20(nm20)
+ ._m21(nm21)
+ ._m22(m22)
+ ._m30(nm30)
+ ._m31(nm31)
+ ._m32(m32)
+ ._properties(properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION));
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the Z axis.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation matrix without pre-multiplying the rotation
+ * transformation, use {@link #rotationZ(float) rotationY()}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotationY(float)
+ *
+ * @param ang
+ * the angle in radians to rotate about the Z axis
+ * @return this
+ */
+ public Matrix4x3f rotateLocalZ(float ang) {
+ return rotateLocalZ(ang, this);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4x3f translate(Vector3fc offset) {
+ return translate(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f translate(Vector3fc offset, Matrix4x3f dest) {
+ return translate(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f translate(float x, float y, float z, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.translation(x, y, z);
+ return translateGeneric(x, y, z, dest);
+ }
+ private Matrix4x3f translateGeneric(float x, float y, float z, Matrix4x3f dest) {
+ MemUtil.INSTANCE.copy(this, dest);
+ dest.m30 = m00 * x + m10 * y + m20 * z + m30;
+ dest.m31 = m01 * x + m11 * y + m21 * z + m31;
+ dest.m32 = m02 * x + m12 * y + m22 * z + m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY);
+ return dest;
+ }
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * In order to set the matrix to a translation transformation without post-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3f translate(float x, float y, float z) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return translation(x, y, z);
+ Matrix4x3f c = this;
+ c.m30 = c.m00 * x + c.m10 * y + c.m20 * z + c.m30;
+ c.m31 = c.m01 * x + c.m11 * y + c.m21 * z + c.m31;
+ c.m32 = c.m02 * x + c.m12 * y + c.m22 * z + c.m32;
+ c.properties &= ~(PROPERTY_IDENTITY);
+ return this;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @return this
+ */
+ public Matrix4x3f translateLocal(Vector3fc offset) {
+ return translateLocal(offset.x(), offset.y(), offset.z());
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(Vector3fc)}.
+ *
+ * @see #translation(Vector3fc)
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f translateLocal(Vector3fc offset, Matrix4x3f dest) {
+ return translateLocal(offset.x(), offset.y(), offset.z(), dest);
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f translateLocal(float x, float y, float z, Matrix4x3f dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.m30 = m30 + x;
+ dest.m31 = m31 + y;
+ dest.m32 = m32 + z;
+ dest.properties = properties & ~(PROPERTY_IDENTITY);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * In order to set the matrix to a translation transformation without pre-multiplying
+ * it, use {@link #translation(float, float, float)}.
+ *
+ * @see #translation(float, float, float)
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @return this
+ */
+ public Matrix4x3f translateLocal(float x, float y, float z) {
+ return translateLocal(x, y, z, this);
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(m00);
+ out.writeFloat(m01);
+ out.writeFloat(m02);
+ out.writeFloat(m10);
+ out.writeFloat(m11);
+ out.writeFloat(m12);
+ out.writeFloat(m20);
+ out.writeFloat(m21);
+ out.writeFloat(m22);
+ out.writeFloat(m30);
+ out.writeFloat(m31);
+ out.writeFloat(m32);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ m00 = in.readFloat();
+ m01 = in.readFloat();
+ m02 = in.readFloat();
+ m10 = in.readFloat();
+ m11 = in.readFloat();
+ m12 = in.readFloat();
+ m20 = in.readFloat();
+ m21 = in.readFloat();
+ m22 = in.readFloat();
+ m30 = in.readFloat();
+ m31 = in.readFloat();
+ m32 = in.readFloat();
+ determineProperties();
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar);
+ float rm30 = (left + right) / (left - right);
+ float rm31 = (top + bottom) / (bottom - top);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f ortho(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4x3f dest) {
+ return ortho(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ return ortho(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho(float, float, float, float, float, float) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f ortho(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return ortho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear);
+ float rm30 = (left + right) / (left - right);
+ float rm31 = (top + bottom) / (bottom - top);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4x3f dest) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float, boolean) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrthoLH(float, float, float, float, float, float) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return orthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(float, float, float, float, float, float, boolean) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f setOrtho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.identity(this);
+ m00 = 2.0f / (right - left);
+ m11 = 2.0f / (top - bottom);
+ m22 = (zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar);
+ m30 = (right + left) / (left - right);
+ m31 = (top + bottom) / (bottom - top);
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho(float, float, float, float, float, float) ortho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f setOrtho(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return setOrtho(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(float, float, float, float, float, float, boolean) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float, boolean)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f setOrthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.identity(this);
+ m00 = 2.0f / (right - left);
+ m11 = 2.0f / (top - bottom);
+ m22 = (zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear);
+ m30 = (right + left) / (left - right);
+ m31 = (top + bottom) / (bottom - top);
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #orthoLH(float, float, float, float, float, float) orthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f setOrthoLH(float left, float right, float bottom, float top, float zNear, float zFar) {
+ return setOrthoLH(left, right, bottom, top, zNear, zFar, false);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, boolean, Matrix4x3f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4x3f orthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / width;
+ float rm11 = 2.0f / height;
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m20 * rm32 + m30;
+ dest.m31 = m21 * rm32 + m31;
+ dest.m32 = m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4x3f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f orthoSymmetric(float width, float height, float zNear, float zFar, Matrix4x3f dest) {
+ return orthoSymmetric(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, boolean) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float, boolean) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f orthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ return orthoSymmetric(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetric(float, float, float, float) setOrthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetric(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f orthoSymmetric(float width, float height, float zNear, float zFar) {
+ return orthoSymmetric(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, boolean, Matrix4x3f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ public Matrix4x3f orthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / width;
+ float rm11 = 2.0f / height;
+ float rm22 = (zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear);
+ float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m20 * rm32 + m30;
+ dest.m31 = m21 * rm32 + m31;
+ dest.m32 = m22 * rm32 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20 * rm22;
+ dest.m21 = m21 * rm22;
+ dest.m22 = m22 * rm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4x3f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f orthoSymmetricLH(float width, float height, float zNear, float zFar, Matrix4x3f dest) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, dest);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, boolean) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float, boolean) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f orthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ return orthoSymmetricLH(width, height, zNear, zFar, zZeroToOne, this);
+ }
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to a symmetric orthographic projection without post-multiplying it,
+ * use {@link #setOrthoSymmetricLH(float, float, float, float) setOrthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoSymmetricLH(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f orthoSymmetricLH(float width, float height, float zNear, float zFar) {
+ return orthoSymmetricLH(width, height, zNear, zFar, false, this);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(float, float, float, float, boolean) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f setOrthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.identity(this);
+ m00 = 2.0f / width;
+ m11 = 2.0f / height;
+ m22 = (zZeroToOne ? 1.0f : 2.0f) / (zNear - zFar);
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetric(float, float, float, float) orthoSymmetric()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetric(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f setOrthoSymmetric(float width, float height, float zNear, float zFar) {
+ return setOrthoSymmetric(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system using the given NDC z range.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float, boolean) setOrtho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(float, float, float, float, boolean) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(float, float, float, float, boolean)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return this
+ */
+ public Matrix4x3f setOrthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne) {
+ MemUtil.INSTANCE.identity(this);
+ m00 = 2.0f / width;
+ m11 = 2.0f / height;
+ m22 = (zZeroToOne ? 1.0f : 2.0f) / (zFar - zNear);
+ m32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
.
+ *
+ * This method is equivalent to calling {@link #setOrthoLH(float, float, float, float, float, float) setOrthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * In order to apply the symmetric orthographic projection to an already existing transformation,
+ * use {@link #orthoSymmetricLH(float, float, float, float) orthoSymmetricLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoSymmetricLH(float, float, float, float)
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @return this
+ */
+ public Matrix4x3f setOrthoSymmetricLH(float width, float height, float zNear, float zFar) {
+ return setOrthoSymmetricLH(width, height, zNear, zFar, false);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix
+ * and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4x3f) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(float, float, float, float) setOrtho()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float, Matrix4x3f)
+ * @see #setOrtho2D(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f ortho2D(float left, float right, float bottom, float top, Matrix4x3f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm30 = -(right + left) / (right - left);
+ float rm31 = -(top + bottom) / (top - bottom);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = -m20;
+ dest.m21 = -m21;
+ dest.m22 = -m22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2D(float, float, float, float) setOrtho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float)
+ * @see #setOrtho2D(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3f ortho2D(float left, float right, float bottom, float top) {
+ return ortho2D(left, right, bottom, top, this);
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4x3f) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(float, float, float, float) setOrthoLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float, Matrix4x3f)
+ * @see #setOrtho2DLH(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f ortho2DLH(float left, float right, float bottom, float top, Matrix4x3f dest) {
+ // calculate right matrix elements
+ float rm00 = 2.0f / (right - left);
+ float rm11 = 2.0f / (top - bottom);
+ float rm30 = -(right + left) / (right - left);
+ float rm31 = -(top + bottom) / (top - bottom);
+
+ // perform optimized multiplication
+ // compute the last column first, because other columns do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m32;
+ dest.m00 = m00 * rm00;
+ dest.m01 = m01 * rm00;
+ dest.m02 = m02 * rm00;
+ dest.m10 = m10 * rm11;
+ dest.m11 = m11 * rm11;
+ dest.m12 = m12 * rm11;
+ dest.m20 = m20;
+ dest.m21 = m21;
+ dest.m22 = m22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * In order to set the matrix to an orthographic projection without post-multiplying it,
+ * use {@link #setOrtho2DLH(float, float, float, float) setOrtho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float)
+ * @see #setOrtho2DLH(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3f ortho2DLH(float left, float right, float bottom, float top) {
+ return ortho2DLH(left, right, bottom, top, this);
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a right-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float) setOrtho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2D(float, float, float, float) ortho2D()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrtho(float, float, float, float, float, float)
+ * @see #ortho2D(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3f setOrtho2D(float left, float right, float bottom, float top) {
+ MemUtil.INSTANCE.identity(this);
+ m00 = 2.0f / (right - left);
+ m11 = 2.0f / (top - bottom);
+ m22 = -1.0f;
+ m30 = -(right + left) / (right - left);
+ m31 = -(top + bottom) / (top - bottom);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Set this matrix to be an orthographic projection transformation for a left-handed coordinate system.
+ *
+ * This method is equivalent to calling {@link #setOrtho(float, float, float, float, float, float) setOrthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * In order to apply the orthographic projection to an already existing transformation,
+ * use {@link #ortho2DLH(float, float, float, float) ortho2DLH()}.
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #setOrthoLH(float, float, float, float, float, float)
+ * @see #ortho2DLH(float, float, float, float)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @return this
+ */
+ public Matrix4x3f setOrtho2DLH(float left, float right, float bottom, float top) {
+ MemUtil.INSTANCE.identity(this);
+ m00 = 2.0f / (right - left);
+ m11 = 2.0f / (top - bottom);
+ m22 = 1.0f;
+ m30 = -(right + left) / (right - left);
+ m31 = -(top + bottom) / (top - bottom);
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3fc, Vector3fc, Vector3fc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}.
+ *
+ * @see #lookAlong(float, float, float, float, float, float)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3f lookAlong(Vector3fc dir, Vector3fc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3fc, Vector3fc, Vector3fc) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(Vector3fc, Vector3fc) setLookAlong()}.
+ *
+ * @see #lookAlong(float, float, float, float, float, float)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f lookAlong(Vector3fc dir, Vector3fc up, Matrix4x3f dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()}
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return setLookAlong(dirX, dirY, dirZ, upX, upY, upZ);
+
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm00 = leftX;
+ float rm01 = upnX;
+ float rm02 = dirX;
+ float rm10 = leftY;
+ float rm11 = upnY;
+ float rm12 = dirY;
+ float rm20 = leftZ;
+ float rm21 = upnZ;
+ float rm22 = dirZ;
+
+ // perform optimized matrix multiplication
+ // introduce temporaries for dependent results
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to set the matrix to a lookalong transformation without post-multiplying it,
+ * use {@link #setLookAlong(float, float, float, float, float, float) setLookAlong()}
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc) setLookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(Vector3fc, Vector3fc)}.
+ *
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ * @see #lookAlong(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3f setLookAlong(Vector3fc dir, Vector3fc up) {
+ return setLookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a rotation transformation to make -z
+ * point along dir
.
+ *
+ * This is equivalent to calling
+ * {@link #setLookAt(float, float, float, float, float, float, float, float, float)
+ * setLookAt()} with eye = (0, 0, 0)
and center = dir
.
+ *
+ * In order to apply the lookalong transformation to any previous existing transformation,
+ * use {@link #lookAlong(float, float, float, float, float, float) lookAlong()}
+ *
+ * @see #setLookAlong(float, float, float, float, float, float)
+ * @see #lookAlong(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f setLookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= -invDirLength;
+ dirY *= -invDirLength;
+ dirZ *= -invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+ m30 = 0.0f;
+ m31 = 0.0f;
+ m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+
+ return this;
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system, that aligns
+ * -z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(Vector3fc, Vector3fc, Vector3fc) lookAt()}.
+ *
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3f setLookAt(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return setLookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAt(float, float, float, float, float, float, float, float, float) lookAt}.
+ *
+ * @see #setLookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f setLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+ m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ properties = PROPERTY_ORTHONORMAL;
+
+ return this;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f lookAt(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4x3f dest) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float)
+ * @see #setLookAlong(Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3f lookAt(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return lookAt(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}.
+ *
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f lookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ return lookAtGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4x3f lookAtGeneric(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4x3f dest) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = eyeX - centerX;
+ dirY = eyeY - centerY;
+ dirZ = eyeZ - centerZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm00 = leftX;
+ float rm01 = upnX;
+ float rm02 = dirX;
+ float rm10 = leftY;
+ float rm11 = upnY;
+ float rm12 = dirY;
+ float rm20 = leftZ;
+ float rm21 = upnZ;
+ float rm22 = dirZ;
+ float rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ float rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ float rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ // introduce temporaries for dependent results
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAt(float, float, float, float, float, float, float, float, float) setLookAt()}.
+ *
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAt(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f lookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ return lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system, that aligns
+ * +z
with center - eye
.
+ *
+ * In order to not make use of vectors to specify eye
, center
and up
but use primitives,
+ * like in the GLU function, use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}
+ * instead.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(Vector3fc, Vector3fc, Vector3fc) lookAt()}.
+ *
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3f setLookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return setLookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to be a "lookat" transformation for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * In order to apply the lookat transformation to a previous existing transformation,
+ * use {@link #lookAtLH(float, float, float, float, float, float, float, float, float) lookAtLH}.
+ *
+ * @see #setLookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f setLookAtLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ m00 = leftX;
+ m01 = upnX;
+ m02 = dirX;
+ m10 = leftY;
+ m11 = upnY;
+ m12 = dirY;
+ m20 = leftZ;
+ m21 = upnZ;
+ m22 = dirZ;
+ m30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ m31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ m32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+ properties = PROPERTY_ORTHONORMAL;
+
+ return this;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f lookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4x3f dest) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @return this
+ */
+ public Matrix4x3f lookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up) {
+ return lookAtLH(eye.x(), eye.y(), eye.z(), center.x(), center.y(), center.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f lookAtLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.setLookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+ return lookAtLHGeneric(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, dest);
+ }
+ private Matrix4x3f lookAtLHGeneric(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ, Matrix4x3f dest) {
+ // Compute direction from position to lookAt
+ float dirX, dirY, dirZ;
+ dirX = centerX - eyeX;
+ dirY = centerY - eyeY;
+ dirZ = centerZ - eyeZ;
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLength;
+ dirY *= invDirLength;
+ dirZ *= invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * dirZ - upZ * dirY;
+ leftY = upZ * dirX - upX * dirZ;
+ leftZ = upX * dirY - upY * dirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirY * leftZ - dirZ * leftY;
+ float upnY = dirZ * leftX - dirX * leftZ;
+ float upnZ = dirX * leftY - dirY * leftX;
+
+ // calculate right matrix elements
+ float rm00 = leftX;
+ float rm01 = upnX;
+ float rm02 = dirX;
+ float rm10 = leftY;
+ float rm11 = upnY;
+ float rm12 = dirY;
+ float rm20 = leftZ;
+ float rm21 = upnZ;
+ float rm22 = dirZ;
+ float rm30 = -(leftX * eyeX + leftY * eyeY + leftZ * eyeZ);
+ float rm31 = -(upnX * eyeX + upnY * eyeY + upnZ * eyeZ);
+ float rm32 = -(dirX * eyeX + dirY * eyeY + dirZ * eyeZ);
+
+ // perform optimized matrix multiplication
+ // compute last column first, because others do not depend on it
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ // introduce temporaries for dependent results
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ // set the rest of the matrix elements
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a lookat transformation without post-multiplying it,
+ * use {@link #setLookAtLH(float, float, float, float, float, float, float, float, float) setLookAtLH()}.
+ *
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc)
+ * @see #setLookAtLH(float, float, float, float, float, float, float, float, float)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f lookAtLH(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ return lookAtLH(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotate(Quaternionfc quat, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.rotation(quat);
+ else if ((properties & PROPERTY_TRANSLATION) != 0)
+ return rotateTranslation(quat, dest);
+ return rotateGeneric(quat, dest);
+ }
+ private Matrix4x3f rotateGeneric(Quaternionfc quat, Matrix4x3f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = dxy - dzw;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3f rotate(Quaternionfc quat) {
+ return rotate(quat, this);
+ }
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateTranslation(Quaternionfc quat, Matrix4x3f dest) {
+ float w2 = quat.w() * quat.w(), x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y(), z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w(), dzw = zw + zw, xy = quat.x() * quat.y(), dxy = xy + xy;
+ float xz = quat.x() * quat.z(), dxz = xz + xz, yw = quat.y() * quat.w(), dyw = yw + yw;
+ float yz = quat.y() * quat.z(), dyz = yz + yz, xw = quat.x() * quat.w(), dxw = xw + xw;
+ float rm00 = w2 + x2 - z2 - y2;
+ float rm01 = dxy + dzw;
+ float rm02 = dxz - dyw;
+ float rm10 = dxy - dzw;
+ float rm11 = y2 - z2 + w2 - x2;
+ float rm12 = dyz + dxw;
+ float rm20 = dyw + dxz;
+ float rm21 = dyz - dxw;
+ float rm22 = z2 - y2 - x2 + w2;
+ dest.m20 = rm20;
+ dest.m21 = rm21;
+ dest.m22 = rm22;
+ dest.m00 = rm00;
+ dest.m01 = rm01;
+ dest.m02 = rm02;
+ dest.m10 = rm10;
+ dest.m11 = rm11;
+ dest.m12 = rm12;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateLocal(Quaternionfc quat, Matrix4x3f dest) {
+ float w2 = quat.w() * quat.w();
+ float x2 = quat.x() * quat.x();
+ float y2 = quat.y() * quat.y();
+ float z2 = quat.z() * quat.z();
+ float zw = quat.z() * quat.w();
+ float xy = quat.x() * quat.y();
+ float xz = quat.x() * quat.z();
+ float yw = quat.y() * quat.w();
+ float yz = quat.y() * quat.z();
+ float xw = quat.x() * quat.w();
+ float lm00 = w2 + x2 - z2 - y2;
+ float lm01 = xy + zw + zw + xy;
+ float lm02 = xz - yw + xz - yw;
+ float lm10 = -zw + xy - zw + xy;
+ float lm11 = y2 - z2 + w2 - x2;
+ float lm12 = yz + yz + xw + xw;
+ float lm20 = yw + xz + xz + yw;
+ float lm21 = yz + yz - xw - xw;
+ float lm22 = z2 - y2 - x2 + w2;
+ float nm00 = lm00 * m00 + lm10 * m01 + lm20 * m02;
+ float nm01 = lm01 * m00 + lm11 * m01 + lm21 * m02;
+ float nm02 = lm02 * m00 + lm12 * m01 + lm22 * m02;
+ float nm10 = lm00 * m10 + lm10 * m11 + lm20 * m12;
+ float nm11 = lm01 * m10 + lm11 * m11 + lm21 * m12;
+ float nm12 = lm02 * m10 + lm12 * m11 + lm22 * m12;
+ float nm20 = lm00 * m20 + lm10 * m21 + lm20 * m22;
+ float nm21 = lm01 * m20 + lm11 * m21 + lm21 * m22;
+ float nm22 = lm02 * m20 + lm12 * m21 + lm22 * m22;
+ float nm30 = lm00 * m30 + lm10 * m31 + lm20 * m32;
+ float nm31 = lm01 * m30 + lm11 * m31 + lm21 * m32;
+ float nm32 = lm02 * m30 + lm12 * m31 + lm22 * m32;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = nm30;
+ dest.m31 = nm31;
+ dest.m32 = nm32;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * In order to set the matrix to a rotation transformation without pre-multiplying,
+ * use {@link #rotation(Quaternionfc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotation(Quaternionfc)
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @return this
+ */
+ public Matrix4x3f rotateLocal(Quaternionfc quat) {
+ return rotateLocal(quat, this);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f}, to this matrix.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3f rotate(AxisAngle4f axisAngle) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(AxisAngle4f)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(AxisAngle4f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotate(AxisAngle4f axisAngle, Matrix4x3f dest) {
+ return rotate(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z, dest);
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis, to this matrix.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis-angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(float, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3f rotate(float angle, Vector3fc axis) {
+ return rotate(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis-angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying,
+ * use {@link #rotation(float, Vector3fc)}.
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float)
+ * @see #rotation(float, Vector3fc)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotate(float angle, Vector3fc axis, Matrix4x3f dest) {
+ return rotate(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ public Matrix4x3f reflect(float a, float b, float c, float d, Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.reflection(a, b, c, d);
+
+ float da = a + a, db = b + b, dc = c + c, dd = d + d;
+ float rm00 = 1.0f - da * a;
+ float rm01 = -da * b;
+ float rm02 = -da * c;
+ float rm10 = -db * a;
+ float rm11 = 1.0f - db * b;
+ float rm12 = -db * c;
+ float rm20 = -dc * a;
+ float rm21 = -dc * b;
+ float rm22 = 1.0f - dc * c;
+ float rm30 = -dd * a;
+ float rm31 = -dd * b;
+ float rm32 = -dd * c;
+
+ // matrix multiplication
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+
+ return dest;
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3f reflect(float a, float b, float c, float d) {
+ return reflect(a, b, c, d, this);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4x3f reflect(float nx, float ny, float nz, float px, float py, float pz) {
+ return reflect(nx, ny, nz, px, py, pz, this);
+ }
+
+ public Matrix4x3f reflect(float nx, float ny, float nz, float px, float py, float pz, Matrix4x3f dest) {
+ float invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ float nnx = nx * invLength;
+ float nny = ny * invLength;
+ float nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflect(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz, dest);
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3f reflect(Vector3fc normal, Vector3fc point) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3f reflect(Quaternionfc orientation, Vector3fc point) {
+ return reflect(orientation, point, this);
+ }
+
+ public Matrix4x3f reflect(Quaternionfc orientation, Vector3fc point, Matrix4x3f dest) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ float normalX = (float) (orientation.x() * num3 + orientation.w() * num2);
+ float normalY = (float) (orientation.y() * num3 - orientation.w() * num1);
+ float normalZ = (float) (1.0 - (orientation.x() * num1 + orientation.y() * num2));
+ return reflect(normalX, normalY, normalZ, point.x(), point.y(), point.z(), dest);
+ }
+
+ public Matrix4x3f reflect(Vector3fc normal, Vector3fc point, Matrix4x3f dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z(), dest);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3f reflection(float a, float b, float c, float d) {
+ float da = a + a, db = b + b, dc = c + c, dd = d + d;
+ m00 = 1.0f - da * a;
+ m01 = -da * b;
+ m02 = -da * c;
+ m10 = -db * a;
+ m11 = 1.0f - db * b;
+ m12 = -db * c;
+ m20 = -dc * a;
+ m21 = -dc * b;
+ m22 = 1.0f - dc * c;
+ m30 = -dd * a;
+ m31 = -dd * b;
+ m32 = -dd * c;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @return this
+ */
+ public Matrix4x3f reflection(float nx, float ny, float nz, float px, float py, float pz) {
+ float invLength = Math.invsqrt(nx * nx + ny * ny + nz * nz);
+ float nnx = nx * invLength;
+ float nny = ny * invLength;
+ float nnz = nz * invLength;
+ /* See: http://mathworld.wolfram.com/Plane.html */
+ return reflection(nnx, nny, nnz, -nnx * px - nny * py - nnz * pz);
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about the given plane
+ * specified via the plane normal and a point on the plane.
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3f reflection(Vector3fc normal, Vector3fc point) {
+ return reflection(normal.x(), normal.y(), normal.z(), point.x(), point.y(), point.z());
+ }
+
+ /**
+ * Set this matrix to a mirror/reflection transformation that reflects about a plane
+ * specified via the plane orientation and a point on the plane.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * @param orientation
+ * the plane orientation
+ * @param point
+ * a point on the plane
+ * @return this
+ */
+ public Matrix4x3f reflection(Quaternionfc orientation, Vector3fc point) {
+ double num1 = orientation.x() + orientation.x();
+ double num2 = orientation.y() + orientation.y();
+ double num3 = orientation.z() + orientation.z();
+ float normalX = (float) (orientation.x() * num3 + orientation.w() * num2);
+ float normalY = (float) (orientation.y() * num3 - orientation.w() * num1);
+ float normalZ = (float) (1.0 - (orientation.x() * num1 + orientation.y() * num2));
+ return reflection(normalX, normalY, normalZ, point.x(), point.y(), point.z());
+ }
+
+ public Vector4f getRow(int row, Vector4f dest) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ dest.x = m00;
+ dest.y = m10;
+ dest.z = m20;
+ dest.w = m30;
+ break;
+ case 1:
+ dest.x = m01;
+ dest.y = m11;
+ dest.z = m21;
+ dest.w = m31;
+ break;
+ case 2:
+ dest.x = m02;
+ dest.y = m12;
+ dest.z = m22;
+ dest.w = m32;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param src
+ * the row components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ public Matrix4x3f setRow(int row, Vector4fc src) throws IndexOutOfBoundsException {
+ switch (row) {
+ case 0:
+ this.m00 = src.x();
+ this.m10 = src.y();
+ this.m20 = src.z();
+ this.m30 = src.w();
+ break;
+ case 1:
+ this.m01 = src.x();
+ this.m11 = src.y();
+ this.m21 = src.z();
+ this.m31 = src.w();
+ break;
+ case 2:
+ this.m02 = src.x();
+ this.m12 = src.y();
+ this.m22 = src.z();
+ this.m32 = src.w();
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ properties = 0;
+ return this;
+ }
+
+ public Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ dest.x = m00;
+ dest.y = m01;
+ dest.z = m02;
+ break;
+ case 1:
+ dest.x = m10;
+ dest.y = m11;
+ dest.z = m12;
+ break;
+ case 2:
+ dest.x = m20;
+ dest.y = m21;
+ dest.z = m22;
+ break;
+ case 3:
+ dest.x = m30;
+ dest.y = m31;
+ dest.z = m32;
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ return dest;
+ }
+
+ /**
+ * Set the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..3]
+ * @param src
+ * the column components to set
+ * @return this
+ * @throws IndexOutOfBoundsException if column
is not in [0..3]
+ */
+ public Matrix4x3f setColumn(int column, Vector3fc src) throws IndexOutOfBoundsException {
+ switch (column) {
+ case 0:
+ this.m00 = src.x();
+ this.m01 = src.y();
+ this.m02 = src.z();
+ break;
+ case 1:
+ this.m10 = src.x();
+ this.m11 = src.y();
+ this.m12 = src.z();
+ break;
+ case 2:
+ this.m20 = src.x();
+ this.m21 = src.y();
+ this.m22 = src.z();
+ break;
+ case 3:
+ this.m30 = src.x();
+ this.m31 = src.y();
+ this.m32 = src.z();
+ break;
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ properties = 0;
+ return this;
+ }
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into the left 3x3 submatrix of this
.
+ * All other values of this
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4x3fc)} to set a given Matrix4x3f to only the left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see #set3x3(Matrix4x3fc)
+ *
+ * @return this
+ */
+ public Matrix4x3f normal() {
+ return normal(this);
+ }
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into the left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * Please note that, if this
is an orthogonal matrix or a matrix whose columns are orthogonal vectors,
+ * then this method need not be invoked, since in that case this
itself is its normal matrix.
+ * In that case, use {@link #set3x3(Matrix4x3fc)} to set a given Matrix4x3f to only the left 3x3 submatrix
+ * of this matrix.
+ *
+ * @see #set3x3(Matrix4x3fc)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f normal(Matrix4x3f dest) {
+ if ((properties & PROPERTY_IDENTITY) != 0)
+ return dest.identity();
+ else if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix4x3f normalOrthonormal(Matrix4x3f dest) {
+ if (dest != this)
+ dest.set(this);
+ return dest._properties(PROPERTY_ORTHONORMAL);
+ }
+ private Matrix4x3f normalGeneric(Matrix4x3f dest) {
+ float m00m11 = m00 * m11;
+ float m01m10 = m01 * m10;
+ float m02m10 = m02 * m10;
+ float m00m12 = m00 * m12;
+ float m01m12 = m01 * m12;
+ float m02m11 = m02 * m11;
+ float det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ float s = 1.0f / det;
+ /* Invert and transpose in one go */
+ float nm00 = (m11 * m22 - m21 * m12) * s;
+ float nm01 = (m20 * m12 - m10 * m22) * s;
+ float nm02 = (m10 * m21 - m20 * m11) * s;
+ float nm10 = (m21 * m02 - m01 * m22) * s;
+ float nm11 = (m00 * m22 - m20 * m02) * s;
+ float nm12 = (m20 * m01 - m00 * m21) * s;
+ float nm20 = (m01m12 - m02m11) * s;
+ float nm21 = (m02m10 - m00m12) * s;
+ float nm22 = (m00m11 - m01m10) * s;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = 0.0f;
+ dest.m31 = 0.0f;
+ dest.m32 = 0.0f;
+ dest.properties = properties & ~PROPERTY_TRANSLATION;
+ return dest;
+ }
+
+ public Matrix3f normal(Matrix3f dest) {
+ if ((properties & PROPERTY_ORTHONORMAL) != 0)
+ return normalOrthonormal(dest);
+ return normalGeneric(dest);
+ }
+ private Matrix3f normalOrthonormal(Matrix3f dest) {
+ return dest.set(this);
+ }
+ private Matrix3f normalGeneric(Matrix3f dest) {
+ float m00m11 = m00 * m11;
+ float m01m10 = m01 * m10;
+ float m02m10 = m02 * m10;
+ float m00m12 = m00 * m12;
+ float m01m12 = m01 * m12;
+ float m02m11 = m02 * m11;
+ float det = (m00m11 - m01m10) * m22 + (m02m10 - m00m12) * m21 + (m01m12 - m02m11) * m20;
+ float s = 1.0f / det;
+ /* Invert and transpose in one go */
+ dest.m00((m11 * m22 - m21 * m12) * s);
+ dest.m01((m20 * m12 - m10 * m22) * s);
+ dest.m02((m10 * m21 - m20 * m11) * s);
+ dest.m10((m21 * m02 - m01 * m22) * s);
+ dest.m11((m00 * m22 - m20 * m02) * s);
+ dest.m12((m20 * m01 - m00 * m21) * s);
+ dest.m20((m01m12 - m02m11) * s);
+ dest.m21((m02m10 - m00m12) * s);
+ dest.m22((m00m11 - m01m10) * s);
+ return dest;
+ }
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal()} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @return this
+ */
+ public Matrix4x3f cofactor3x3() {
+ return cofactor3x3(this);
+ }
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix3f cofactor3x3(Matrix3f dest) {
+ dest.m00 = m11 * m22 - m21 * m12;
+ dest.m01 = m20 * m12 - m10 * m22;
+ dest.m02 = m10 * m21 - m20 * m11;
+ dest.m10 = m21 * m02 - m01 * m22;
+ dest.m11 = m00 * m22 - m20 * m02;
+ dest.m12 = m20 * m01 - m00 * m21;
+ dest.m20 = m01 * m12 - m02 * m11;
+ dest.m21 = m02 * m10 - m00 * m12;
+ dest.m22 = m00 * m11 - m01 * m10;
+ return dest;
+ }
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to {@link #identity() identity}.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4x3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f cofactor3x3(Matrix4x3f dest) {
+ float nm00 = m11 * m22 - m21 * m12;
+ float nm01 = m20 * m12 - m10 * m22;
+ float nm02 = m10 * m21 - m20 * m11;
+ float nm10 = m21 * m02 - m01 * m22;
+ float nm11 = m00 * m22 - m20 * m02;
+ float nm12 = m20 * m01 - m00 * m21;
+ float nm20 = m01 * m12 - m11 * m02;
+ float nm21 = m02 * m10 - m12 * m00;
+ float nm22 = m00 * m11 - m10 * m01;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m30 = 0.0f;
+ dest.m31 = 0.0f;
+ dest.m32 = 0.0f;
+ dest.properties = properties & ~PROPERTY_TRANSLATION;
+ return dest;
+ }
+
+ /**
+ * Normalize the left 3x3 submatrix of this matrix.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @return this
+ */
+ public Matrix4x3f normalize3x3() {
+ return normalize3x3(this);
+ }
+
+ public Matrix4x3f normalize3x3(Matrix4x3f dest) {
+ float invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ float invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ float invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ dest.m00 = m00 * invXlen; dest.m01 = m01 * invXlen; dest.m02 = m02 * invXlen;
+ dest.m10 = m10 * invYlen; dest.m11 = m11 * invYlen; dest.m12 = m12 * invYlen;
+ dest.m20 = m20 * invZlen; dest.m21 = m21 * invZlen; dest.m22 = m22 * invZlen;
+ dest.properties = properties;
+ return dest;
+ }
+
+ public Matrix3f normalize3x3(Matrix3f dest) {
+ float invXlen = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ float invYlen = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ float invZlen = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ dest.m00(m00 * invXlen); dest.m01(m01 * invXlen); dest.m02(m02 * invXlen);
+ dest.m10(m10 * invYlen); dest.m11(m11 * invYlen); dest.m12(m12 * invYlen);
+ dest.m20(m20 * invZlen); dest.m21(m21 * invZlen); dest.m22(m22 * invZlen);
+ return dest;
+ }
+
+ public Vector4f frustumPlane(int which, Vector4f dest) {
+ switch (which) {
+ case PLANE_NX:
+ dest.set(m00, m10, m20, 1.0f + m30).normalize();
+ break;
+ case PLANE_PX:
+ dest.set(-m00, -m10, -m20, 1.0f - m30).normalize();
+ break;
+ case PLANE_NY:
+ dest.set(m01, m11, m21, 1.0f + m31).normalize();
+ break;
+ case PLANE_PY:
+ dest.set(-m01, -m11, -m21, 1.0f - m31).normalize();
+ break;
+ case PLANE_NZ:
+ dest.set(m02, m12, m22, 1.0f + m32).normalize();
+ break;
+ case PLANE_PZ:
+ dest.set(-m02, -m12, -m22, 1.0f - m32).normalize();
+ break;
+ default:
+ throw new IllegalArgumentException("which"); //$NON-NLS-1$
+ }
+ return dest;
+ }
+
+ public Vector3f positiveZ(Vector3f dir) {
+ dir.x = m10 * m21 - m11 * m20;
+ dir.y = m20 * m01 - m21 * m00;
+ dir.z = m00 * m11 - m01 * m10;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f normalizedPositiveZ(Vector3f dir) {
+ dir.x = m02;
+ dir.y = m12;
+ dir.z = m22;
+ return dir;
+ }
+
+ public Vector3f positiveX(Vector3f dir) {
+ dir.x = m11 * m22 - m12 * m21;
+ dir.y = m02 * m21 - m01 * m22;
+ dir.z = m01 * m12 - m02 * m11;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f normalizedPositiveX(Vector3f dir) {
+ dir.x = m00;
+ dir.y = m10;
+ dir.z = m20;
+ return dir;
+ }
+
+ public Vector3f positiveY(Vector3f dir) {
+ dir.x = m12 * m20 - m10 * m22;
+ dir.y = m00 * m22 - m02 * m20;
+ dir.z = m02 * m10 - m00 * m12;
+ return dir.normalize(dir);
+ }
+
+ public Vector3f normalizedPositiveY(Vector3f dir) {
+ dir.x = m01;
+ dir.y = m11;
+ dir.z = m21;
+ return dir;
+ }
+
+ public Vector3f origin(Vector3f origin) {
+ float a = m00 * m11 - m01 * m10;
+ float b = m00 * m12 - m02 * m10;
+ float d = m01 * m12 - m02 * m11;
+ float g = m20 * m31 - m21 * m30;
+ float h = m20 * m32 - m22 * m30;
+ float j = m21 * m32 - m22 * m31;
+ origin.x = -m10 * j + m11 * h - m12 * g;
+ origin.y = m00 * j - m01 * h + m02 * g;
+ origin.z = -m30 * d + m31 * b - m32 * a;
+ return origin;
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3f shadow(Vector4fc light, float a, float b, float c, float d) {
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, this);
+ }
+
+ public Matrix4x3f shadow(Vector4fc light, float a, float b, float c, float d, Matrix4x3f dest) {
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @return this
+ */
+ public Matrix4x3f shadow(float lightX, float lightY, float lightZ, float lightW, float a, float b, float c, float d) {
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, this);
+ }
+
+ public Matrix4x3f shadow(float lightX, float lightY, float lightZ, float lightW, float a, float b, float c, float d, Matrix4x3f dest) {
+ // normalize plane
+ float invPlaneLen = Math.invsqrt(a*a + b*b + c*c);
+ float an = a * invPlaneLen;
+ float bn = b * invPlaneLen;
+ float cn = c * invPlaneLen;
+ float dn = d * invPlaneLen;
+
+ float dot = an * lightX + bn * lightY + cn * lightZ + dn * lightW;
+
+ // compute right matrix elements
+ float rm00 = dot - an * lightX;
+ float rm01 = -an * lightY;
+ float rm02 = -an * lightZ;
+ float rm03 = -an * lightW;
+ float rm10 = -bn * lightX;
+ float rm11 = dot - bn * lightY;
+ float rm12 = -bn * lightZ;
+ float rm13 = -bn * lightW;
+ float rm20 = -cn * lightX;
+ float rm21 = -cn * lightY;
+ float rm22 = dot - cn * lightZ;
+ float rm23 = -cn * lightW;
+ float rm30 = -dn * lightX;
+ float rm31 = -dn * lightY;
+ float rm32 = -dn * lightZ;
+ float rm33 = dot - dn * lightW;
+
+ // matrix multiplication
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02 + m30 * rm03;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02 + m31 * rm03;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02 + m32 * rm03;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12 + m30 * rm13;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12 + m31 * rm13;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12 + m32 * rm13;
+ float nm20 = m00 * rm20 + m10 * rm21 + m20 * rm22 + m30 * rm23;
+ float nm21 = m01 * rm20 + m11 * rm21 + m21 * rm22 + m31 * rm23;
+ float nm22 = m02 * rm20 + m12 * rm21 + m22 * rm22 + m32 * rm23;
+ dest.m30 = m00 * rm30 + m10 * rm31 + m20 * rm32 + m30 * rm33;
+ dest.m31 = m01 * rm30 + m11 * rm31 + m21 * rm32 + m31 * rm33;
+ dest.m32 = m02 * rm30 + m12 * rm31 + m22 * rm32 + m32 * rm33;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION | PROPERTY_ORTHONORMAL);
+
+ return dest;
+ }
+
+ public Matrix4x3f shadow(Vector4fc light, Matrix4x3fc planeTransform, Matrix4x3f dest) {
+ // compute plane equation by transforming (y = 0)
+ float a = planeTransform.m10();
+ float b = planeTransform.m11();
+ float c = planeTransform.m12();
+ float d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(light.x(), light.y(), light.z(), light.w(), a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4x3f shadow(Vector4fc light, Matrix4x3fc planeTransform) {
+ return shadow(light, planeTransform, this);
+ }
+
+ public Matrix4x3f shadow(float lightX, float lightY, float lightZ, float lightW, Matrix4x3fc planeTransform, Matrix4x3f dest) {
+ // compute plane equation by transforming (y = 0)
+ float a = planeTransform.m10();
+ float b = planeTransform.m11();
+ float c = planeTransform.m12();
+ float d = -a * planeTransform.m30() - b * planeTransform.m31() - c * planeTransform.m32();
+ return shadow(lightX, lightY, lightZ, lightW, a, b, c, d, dest);
+ }
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @return this
+ */
+ public Matrix4x3f shadow(float lightX, float lightY, float lightZ, float lightW, Matrix4x3f planeTransform) {
+ return shadow(lightX, lightY, lightZ, lightW, planeTransform, this);
+ }
+
+ /**
+ * Set this matrix to a cylindrical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
while constraining a cylindrical rotation around the given up
vector.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the rotation axis (must be {@link Vector3f#normalize() normalized})
+ * @return this
+ */
+ public Matrix4x3f billboardCylindrical(Vector3fc objPos, Vector3fc targetPos, Vector3fc up) {
+ float dirX = targetPos.x() - objPos.x();
+ float dirY = targetPos.y() - objPos.y();
+ float dirZ = targetPos.z() - objPos.z();
+ // left = up x dir
+ float leftX = up.y() * dirZ - up.z() * dirY;
+ float leftY = up.z() * dirX - up.x() * dirZ;
+ float leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ float invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // recompute dir by constraining rotation around 'up'
+ // dir = left x up
+ dirX = leftY * up.z() - leftZ * up.y();
+ dirY = leftZ * up.x() - leftX * up.z();
+ dirZ = leftX * up.y() - leftY * up.x();
+ // normalize dir
+ float invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // set matrix elements
+ m00 = leftX;
+ m01 = leftY;
+ m02 = leftZ;
+ m10 = up.x();
+ m11 = up.y();
+ m12 = up.z();
+ m20 = dirX;
+ m21 = dirY;
+ m22 = dirZ;
+ m30 = objPos.x();
+ m31 = objPos.y();
+ m32 = objPos.z();
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * If preserving an up vector is not necessary when rotating the +Z axis, then a shortest arc rotation can be obtained
+ * using {@link #billboardSpherical(Vector3fc, Vector3fc)}.
+ *
+ * @see #billboardSpherical(Vector3fc, Vector3fc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @param up
+ * the up axis used to orient the object
+ * @return this
+ */
+ public Matrix4x3f billboardSpherical(Vector3fc objPos, Vector3fc targetPos, Vector3fc up) {
+ float dirX = targetPos.x() - objPos.x();
+ float dirY = targetPos.y() - objPos.y();
+ float dirZ = targetPos.z() - objPos.z();
+ // normalize dir
+ float invDirLen = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ dirX *= invDirLen;
+ dirY *= invDirLen;
+ dirZ *= invDirLen;
+ // left = up x dir
+ float leftX = up.y() * dirZ - up.z() * dirY;
+ float leftY = up.z() * dirX - up.x() * dirZ;
+ float leftZ = up.x() * dirY - up.y() * dirX;
+ // normalize left
+ float invLeftLen = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLen;
+ leftY *= invLeftLen;
+ leftZ *= invLeftLen;
+ // up = dir x left
+ float upX = dirY * leftZ - dirZ * leftY;
+ float upY = dirZ * leftX - dirX * leftZ;
+ float upZ = dirX * leftY - dirY * leftX;
+ // set matrix elements
+ m00 = leftX;
+ m01 = leftY;
+ m02 = leftZ;
+ m10 = upX;
+ m11 = upY;
+ m12 = upZ;
+ m20 = dirX;
+ m21 = dirY;
+ m22 = dirZ;
+ m30 = objPos.x();
+ m31 = objPos.y();
+ m32 = objPos.z();
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a spherical billboard transformation that rotates the local +Z axis of a given object with position objPos
towards
+ * a target position at targetPos
using a shortest arc rotation by not preserving any up vector of the object.
+ *
+ * This method can be used to create the complete model transformation for a given object, including the translation of the object to
+ * its position objPos
.
+ *
+ * In order to specify an up vector which needs to be maintained when rotating the +Z axis of the object,
+ * use {@link #billboardSpherical(Vector3fc, Vector3fc, Vector3fc)}.
+ *
+ * @see #billboardSpherical(Vector3fc, Vector3fc, Vector3fc)
+ *
+ * @param objPos
+ * the position of the object to rotate towards targetPos
+ * @param targetPos
+ * the position of the target (for example the camera) towards which to rotate the object
+ * @return this
+ */
+ public Matrix4x3f billboardSpherical(Vector3fc objPos, Vector3fc targetPos) {
+ float toDirX = targetPos.x() - objPos.x();
+ float toDirY = targetPos.y() - objPos.y();
+ float toDirZ = targetPos.z() - objPos.z();
+ float x = -toDirY;
+ float y = toDirX;
+ float w = Math.sqrt(toDirX * toDirX + toDirY * toDirY + toDirZ * toDirZ) + toDirZ;
+ float invNorm = Math.invsqrt(x * x + y * y + w * w);
+ x *= invNorm;
+ y *= invNorm;
+ w *= invNorm;
+ float q00 = (x + x) * x;
+ float q11 = (y + y) * y;
+ float q01 = (x + x) * y;
+ float q03 = (x + x) * w;
+ float q13 = (y + y) * w;
+ m00 = 1.0f - q11;
+ m01 = q01;
+ m02 = -q13;
+ m10 = q01;
+ m11 = 1.0f - q00;
+ m12 = q03;
+ m20 = q13;
+ m21 = -q03;
+ m22 = 1.0f - q11 - q00;
+ m30 = objPos.x();
+ m31 = objPos.y();
+ m32 = objPos.z();
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(m00);
+ result = prime * result + Float.floatToIntBits(m01);
+ result = prime * result + Float.floatToIntBits(m02);
+ result = prime * result + Float.floatToIntBits(m10);
+ result = prime * result + Float.floatToIntBits(m11);
+ result = prime * result + Float.floatToIntBits(m12);
+ result = prime * result + Float.floatToIntBits(m20);
+ result = prime * result + Float.floatToIntBits(m21);
+ result = prime * result + Float.floatToIntBits(m22);
+ result = prime * result + Float.floatToIntBits(m30);
+ result = prime * result + Float.floatToIntBits(m31);
+ result = prime * result + Float.floatToIntBits(m32);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof Matrix4x3f))
+ return false;
+ Matrix4x3f other = (Matrix4x3f) obj;
+ if (Float.floatToIntBits(m00) != Float.floatToIntBits(other.m00))
+ return false;
+ if (Float.floatToIntBits(m01) != Float.floatToIntBits(other.m01))
+ return false;
+ if (Float.floatToIntBits(m02) != Float.floatToIntBits(other.m02))
+ return false;
+ if (Float.floatToIntBits(m10) != Float.floatToIntBits(other.m10))
+ return false;
+ if (Float.floatToIntBits(m11) != Float.floatToIntBits(other.m11))
+ return false;
+ if (Float.floatToIntBits(m12) != Float.floatToIntBits(other.m12))
+ return false;
+ if (Float.floatToIntBits(m20) != Float.floatToIntBits(other.m20))
+ return false;
+ if (Float.floatToIntBits(m21) != Float.floatToIntBits(other.m21))
+ return false;
+ if (Float.floatToIntBits(m22) != Float.floatToIntBits(other.m22))
+ return false;
+ if (Float.floatToIntBits(m30) != Float.floatToIntBits(other.m30))
+ return false;
+ if (Float.floatToIntBits(m31) != Float.floatToIntBits(other.m31))
+ return false;
+ if (Float.floatToIntBits(m32) != Float.floatToIntBits(other.m32))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Matrix4x3fc m, float delta) {
+ if (this == m)
+ return true;
+ if (m == null)
+ return false;
+ if (!(m instanceof Matrix4x3f))
+ return false;
+ if (!Runtime.equals(m00, m.m00(), delta))
+ return false;
+ if (!Runtime.equals(m01, m.m01(), delta))
+ return false;
+ if (!Runtime.equals(m02, m.m02(), delta))
+ return false;
+ if (!Runtime.equals(m10, m.m10(), delta))
+ return false;
+ if (!Runtime.equals(m11, m.m11(), delta))
+ return false;
+ if (!Runtime.equals(m12, m.m12(), delta))
+ return false;
+ if (!Runtime.equals(m20, m.m20(), delta))
+ return false;
+ if (!Runtime.equals(m21, m.m21(), delta))
+ return false;
+ if (!Runtime.equals(m22, m.m22(), delta))
+ return false;
+ if (!Runtime.equals(m30, m.m30(), delta))
+ return false;
+ if (!Runtime.equals(m31, m.m31(), delta))
+ return false;
+ if (!Runtime.equals(m32, m.m32(), delta))
+ return false;
+ return true;
+ }
+
+ public Matrix4x3f pick(float x, float y, float width, float height, int[] viewport, Matrix4x3f dest) {
+ float sx = viewport[2] / width;
+ float sy = viewport[3] / height;
+ float tx = (viewport[2] + 2.0f * (viewport[0] - x)) / width;
+ float ty = (viewport[3] + 2.0f * (viewport[1] - y)) / height;
+ dest.m30 = m00 * tx + m10 * ty + m30;
+ dest.m31 = m01 * tx + m11 * ty + m31;
+ dest.m32 = m02 * tx + m12 * ty + m32;
+ dest.m00 = m00 * sx;
+ dest.m01 = m01 * sx;
+ dest.m02 = m02 * sx;
+ dest.m10 = m10 * sy;
+ dest.m11 = m11 * sy;
+ dest.m12 = m12 * sy;
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @return this
+ */
+ public Matrix4x3f pick(float x, float y, float width, float height, int[] viewport) {
+ return pick(x, y, width, height, viewport, this);
+ }
+
+ /**
+ * Exchange the values of this
matrix with the given other
matrix.
+ *
+ * @param other
+ * the other matrix to exchange the values with
+ * @return this
+ */
+ public Matrix4x3f swap(Matrix4x3f other) {
+ MemUtil.INSTANCE.swap(this, other);
+ int props = properties;
+ this.properties = other.properties;
+ other.properties = props;
+ return this;
+ }
+
+ public Matrix4x3f arcball(float radius, float centerX, float centerY, float centerZ, float angleX, float angleY, Matrix4x3f dest) {
+ float m30 = m20 * -radius + this.m30;
+ float m31 = m21 * -radius + this.m31;
+ float m32 = m22 * -radius + this.m32;
+ float sin = Math.sin(angleX);
+ float cos = Math.cosFromSin(sin, angleX);
+ float nm10 = m10 * cos + m20 * sin;
+ float nm11 = m11 * cos + m21 * sin;
+ float nm12 = m12 * cos + m22 * sin;
+ float m20 = this.m20 * cos - m10 * sin;
+ float m21 = this.m21 * cos - m11 * sin;
+ float m22 = this.m22 * cos - m12 * sin;
+ sin = Math.sin(angleY);
+ cos = Math.cosFromSin(sin, angleY);
+ float nm00 = m00 * cos - m20 * sin;
+ float nm01 = m01 * cos - m21 * sin;
+ float nm02 = m02 * cos - m22 * sin;
+ float nm20 = m00 * sin + m20 * cos;
+ float nm21 = m01 * sin + m21 * cos;
+ float nm22 = m02 * sin + m22 * cos;
+ dest.m30 = -nm00 * centerX - nm10 * centerY - nm20 * centerZ + m30;
+ dest.m31 = -nm01 * centerX - nm11 * centerY - nm21 * centerZ + m31;
+ dest.m32 = -nm02 * centerX - nm12 * centerY - nm22 * centerZ + m32;
+ dest.m20 = nm20;
+ dest.m21 = nm21;
+ dest.m22 = nm22;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ public Matrix4x3f arcball(float radius, Vector3fc center, float angleX, float angleY, Matrix4x3f dest) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, dest);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4x3f arcball(float radius, float centerX, float centerY, float centerZ, float angleX, float angleY) {
+ return arcball(radius, centerX, centerY, centerZ, angleX, angleY, this);
+ }
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @return this
+ */
+ public Matrix4x3f arcball(float radius, Vector3fc center, float angleX, float angleY) {
+ return arcball(radius, center.x(), center.y(), center.z(), angleX, angleY, this);
+ }
+
+ public Matrix4x3f transformAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Vector3f outMin, Vector3f outMax) {
+ float xax = m00 * minX, xay = m01 * minX, xaz = m02 * minX;
+ float xbx = m00 * maxX, xby = m01 * maxX, xbz = m02 * maxX;
+ float yax = m10 * minY, yay = m11 * minY, yaz = m12 * minY;
+ float ybx = m10 * maxY, yby = m11 * maxY, ybz = m12 * maxY;
+ float zax = m20 * minZ, zay = m21 * minZ, zaz = m22 * minZ;
+ float zbx = m20 * maxZ, zby = m21 * maxZ, zbz = m22 * maxZ;
+ float xminx, xminy, xminz, yminx, yminy, yminz, zminx, zminy, zminz;
+ float xmaxx, xmaxy, xmaxz, ymaxx, ymaxy, ymaxz, zmaxx, zmaxy, zmaxz;
+ if (xax < xbx) {
+ xminx = xax;
+ xmaxx = xbx;
+ } else {
+ xminx = xbx;
+ xmaxx = xax;
+ }
+ if (xay < xby) {
+ xminy = xay;
+ xmaxy = xby;
+ } else {
+ xminy = xby;
+ xmaxy = xay;
+ }
+ if (xaz < xbz) {
+ xminz = xaz;
+ xmaxz = xbz;
+ } else {
+ xminz = xbz;
+ xmaxz = xaz;
+ }
+ if (yax < ybx) {
+ yminx = yax;
+ ymaxx = ybx;
+ } else {
+ yminx = ybx;
+ ymaxx = yax;
+ }
+ if (yay < yby) {
+ yminy = yay;
+ ymaxy = yby;
+ } else {
+ yminy = yby;
+ ymaxy = yay;
+ }
+ if (yaz < ybz) {
+ yminz = yaz;
+ ymaxz = ybz;
+ } else {
+ yminz = ybz;
+ ymaxz = yaz;
+ }
+ if (zax < zbx) {
+ zminx = zax;
+ zmaxx = zbx;
+ } else {
+ zminx = zbx;
+ zmaxx = zax;
+ }
+ if (zay < zby) {
+ zminy = zay;
+ zmaxy = zby;
+ } else {
+ zminy = zby;
+ zmaxy = zay;
+ }
+ if (zaz < zbz) {
+ zminz = zaz;
+ zmaxz = zbz;
+ } else {
+ zminz = zbz;
+ zmaxz = zaz;
+ }
+ outMin.x = xminx + yminx + zminx + m30;
+ outMin.y = xminy + yminy + zminy + m31;
+ outMin.z = xminz + yminz + zminz + m32;
+ outMax.x = xmaxx + ymaxx + zmaxx + m30;
+ outMax.y = xmaxy + ymaxy + zmaxy + m31;
+ outMax.z = xmaxz + ymaxz + zmaxz + m32;
+ return this;
+ }
+
+ public Matrix4x3f transformAab(Vector3fc min, Vector3fc max, Vector3f outMin, Vector3f outMax) {
+ return transformAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), outMin, outMax);
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Matrix4x3f lerp(Matrix4x3fc other, float t) {
+ return lerp(other, t, this);
+ }
+
+ public Matrix4x3f lerp(Matrix4x3fc other, float t, Matrix4x3f dest) {
+ dest.m00 = Math.fma(other.m00() - m00, t, m00);
+ dest.m01 = Math.fma(other.m01() - m01, t, m01);
+ dest.m02 = Math.fma(other.m02() - m02, t, m02);
+ dest.m10 = Math.fma(other.m10() - m10, t, m10);
+ dest.m11 = Math.fma(other.m11() - m11, t, m11);
+ dest.m12 = Math.fma(other.m12() - m12, t, m12);
+ dest.m20 = Math.fma(other.m20() - m20, t, m20);
+ dest.m21 = Math.fma(other.m21() - m21, t, m21);
+ dest.m22 = Math.fma(other.m22() - m22, t, m22);
+ dest.m30 = Math.fma(other.m30() - m30, t, m30);
+ dest.m31 = Math.fma(other.m31() - m31, t, m31);
+ dest.m32 = Math.fma(other.m32() - m32, t, m32);
+ dest.properties = properties & other.properties();
+ return dest;
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3f().lookAt(new Vector3f(), new Vector3f(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(float, float, float, float, float, float, Matrix4x3f)
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateTowards(Vector3fc dir, Vector3fc up, Matrix4x3f dest) {
+ return rotateTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(Vector3fc, Vector3fc) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3f().lookAt(new Vector3f(), new Vector3f(dir).negate(), up).invert())
+ *
+ * @see #rotateTowards(float, float, float, float, float, float)
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ *
+ * @param dir
+ * the direction to orient towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3f rotateTowards(Vector3fc dir, Vector3fc up) {
+ return rotateTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3f().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert())
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ return rotateTowards(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * In order to set the matrix to a rotation transformation without post-multiplying it,
+ * use {@link #rotationTowards(float, float, float, float, float, float) rotationTowards()}.
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3f().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4x3f dest) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ float rm00 = leftX;
+ float rm01 = leftY;
+ float rm02 = leftZ;
+ float rm10 = upnX;
+ float rm11 = upnY;
+ float rm12 = upnZ;
+ float rm20 = ndirX;
+ float rm21 = ndirY;
+ float rm22 = ndirZ;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ float nm00 = m00 * rm00 + m10 * rm01 + m20 * rm02;
+ float nm01 = m01 * rm00 + m11 * rm01 + m21 * rm02;
+ float nm02 = m02 * rm00 + m12 * rm01 + m22 * rm02;
+ float nm10 = m00 * rm10 + m10 * rm11 + m20 * rm12;
+ float nm11 = m01 * rm10 + m11 * rm11 + m21 * rm12;
+ float nm12 = m02 * rm10 + m12 * rm11 + m22 * rm12;
+ dest.m20 = m00 * rm20 + m10 * rm21 + m20 * rm22;
+ dest.m21 = m01 * rm20 + m11 * rm21 + m21 * rm22;
+ dest.m22 = m02 * rm20 + m12 * rm21 + m22 * rm22;
+ dest.m00 = nm00;
+ dest.m01 = nm01;
+ dest.m02 = nm02;
+ dest.m10 = nm10;
+ dest.m11 = nm11;
+ dest.m12 = nm12;
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with dir
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(new Vector3f(), new Vector3f(dir).negate(), up).invert()
+ *
+ * @see #rotationTowards(Vector3fc, Vector3fc)
+ * @see #rotateTowards(float, float, float, float, float, float)
+ *
+ * @param dir
+ * the direction to orient the local -z axis towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3f rotationTowards(Vector3fc dir, Vector3fc up) {
+ return rotationTowards(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that aligns the local -z
axis with (dirX, dirY, dirZ)
.
+ *
+ * In order to apply the rotation transformation to a previous existing transformation,
+ * use {@link #rotateTowards(float, float, float, float, float, float) rotateTowards}.
+ *
+ * This method is equivalent to calling: setLookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert()
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ * @see #rotationTowards(float, float, float, float, float, float)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f rotationTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ this.m30 = 0.0f;
+ this.m31 = 0.0f;
+ this.m32 = 0.0f;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given pos
and aligns the local -z
+ * axis with dir
.
+ *
+ * This method is equivalent to calling: translation(pos).rotateTowards(dir, up)
+ *
+ * @see #translation(Vector3fc)
+ * @see #rotateTowards(Vector3fc, Vector3fc)
+ *
+ * @param pos
+ * the position to translate to
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3f translationRotateTowards(Vector3fc pos, Vector3fc dir, Vector3fc up) {
+ return translationRotateTowards(pos.x(), pos.y(), pos.z(), dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Set this matrix to a model transformation for a right-handed coordinate system,
+ * that translates to the given (posX, posY, posZ)
and aligns the local -z
+ * axis with (dirX, dirY, dirZ)
.
+ *
+ * This method is equivalent to calling: translation(posX, posY, posZ).rotateTowards(dirX, dirY, dirZ, upX, upY, upZ)
+ *
+ * @see #translation(float, float, float)
+ * @see #rotateTowards(float, float, float, float, float, float)
+ *
+ * @param posX
+ * the x-coordinate of the position to translate to
+ * @param posY
+ * the y-coordinate of the position to translate to
+ * @param posZ
+ * the z-coordinate of the position to translate to
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f translationRotateTowards(float posX, float posY, float posZ, float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float ndirX = dirX * invDirLength;
+ float ndirY = dirY * invDirLength;
+ float ndirZ = dirZ * invDirLength;
+ // left = up x direction
+ float leftX, leftY, leftZ;
+ leftX = upY * ndirZ - upZ * ndirY;
+ leftY = upZ * ndirX - upX * ndirZ;
+ leftZ = upX * ndirY - upY * ndirX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = ndirY * leftZ - ndirZ * leftY;
+ float upnY = ndirZ * leftX - ndirX * leftZ;
+ float upnZ = ndirX * leftY - ndirY * leftX;
+ this.m00 = leftX;
+ this.m01 = leftY;
+ this.m02 = leftZ;
+ this.m10 = upnX;
+ this.m11 = upnY;
+ this.m12 = upnZ;
+ this.m20 = ndirX;
+ this.m21 = ndirY;
+ this.m22 = ndirZ;
+ this.m30 = posX;
+ this.m31 = posY;
+ this.m32 = posZ;
+ properties = PROPERTY_ORTHONORMAL;
+ return this;
+ }
+
+ public Vector3f getEulerAnglesZYX(Vector3f dest) {
+ dest.x = Math.atan2(m12, m22);
+ dest.y = Math.atan2(-m02, Math.sqrt(1.0f - m02 * m02));
+ dest.z = Math.atan2(m01, m00);
+ return dest;
+ }
+
+ public Vector3f getEulerAnglesXYZ(Vector3f dest) {
+ dest.x = Math.atan2(-m21, m22);
+ dest.y = Math.atan2(m20, Math.sqrt(1.0f - m20 * m20));
+ dest.z = Math.atan2(-m10, m00);
+ return dest;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @return this
+ */
+ public Matrix4x3f obliqueZ(float a, float b) {
+ this.m20 = m00 * a + m10 * b + m20;
+ this.m21 = m01 * a + m11 * b + m21;
+ this.m22 = m02 * a + m12 * b + m22;
+ this.properties = 0;
+ return this;
+ }
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Matrix4x3f obliqueZ(float a, float b, Matrix4x3f dest) {
+ dest.m00 = m00;
+ dest.m01 = m01;
+ dest.m02 = m02;
+ dest.m10 = m10;
+ dest.m11 = m11;
+ dest.m12 = m12;
+ dest.m20 = m00 * a + m10 * b + m20;
+ dest.m21 = m01 * a + m11 * b + m21;
+ dest.m22 = m02 * a + m12 * b + m22;
+ dest.m30 = m30;
+ dest.m31 = m31;
+ dest.m32 = m32;
+ dest.properties = 0;
+ return dest;
+ }
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector up
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from
+ * {@link #setLookAt(Vector3fc, Vector3fc, Vector3fc)} called with the current
+ * local origin of this matrix (as obtained by {@link #origin(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector up
.
+ *
+ * @param up
+ * the up vector
+ * @return this
+ */
+ public Matrix4x3f withLookAtUp(Vector3fc up) {
+ return withLookAtUp(up.x(), up.y(), up.z(), this);
+ }
+
+ public Matrix4x3f withLookAtUp(Vector3fc up, Matrix4x3f dest) {
+ return withLookAtUp(up.x(), up.y(), up.z());
+ }
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector (upX, upY, upZ)
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from
+ * {@link #setLookAt(float, float, float, float, float, float, float, float, float)} called with the current
+ * local origin of this matrix (as obtained by {@link #origin(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector (upX, upY, upZ)
.
+ *
+ * @param upX
+ * the x coordinate of the up vector
+ * @param upY
+ * the y coordinate of the up vector
+ * @param upZ
+ * the z coordinate of the up vector
+ * @return this
+ */
+ public Matrix4x3f withLookAtUp(float upX, float upY, float upZ) {
+ return withLookAtUp(upX, upY, upZ, this);
+ }
+
+ public Matrix4x3f withLookAtUp(float upX, float upY, float upZ, Matrix4x3f dest) {
+ float y = (upY * m21 - upZ * m11) * m02 +
+ (upZ * m01 - upX * m21) * m12 +
+ (upX * m11 - upY * m01) * m22;
+ float x = upX * m01 + upY * m11 + upZ * m21;
+ if ((properties & PROPERTY_ORTHONORMAL) == 0)
+ x *= Math.sqrt(m01 * m01 + m11 * m11 + m21 * m21);
+ float invsqrt = Math.invsqrt(y * y + x * x);
+ float c = x * invsqrt, s = y * invsqrt;
+ float nm00 = c * m00 - s * m01, nm10 = c * m10 - s * m11, nm20 = c * m20 - s * m21, nm31 = s * m30 + c * m31;
+ float nm01 = s * m00 + c * m01, nm11 = s * m10 + c * m11, nm21 = s * m20 + c * m21, nm30 = c * m30 - s * m31;
+ dest
+ ._m00(nm00)._m10(nm10)._m20(nm20)._m30(nm30)
+ ._m01(nm01)._m11(nm11)._m21(nm21)._m31(nm31);
+ if (dest != this) {
+ dest
+ ._m02(m02)._m12(m12)._m22(m22)._m32(m32);
+ }
+ dest.properties = properties & ~(PROPERTY_IDENTITY | PROPERTY_TRANSLATION);
+ return dest;
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapXZY() {
+ return mapXZY(this);
+ }
+ public Matrix4x3f mapXZY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapXZnY() {
+ return mapXZnY(this);
+ }
+ public Matrix4x3f mapXZnY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapXnYnZ() {
+ return mapXnYnZ(this);
+ }
+ public Matrix4x3f mapXnYnZ(Matrix4x3f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapXnZY() {
+ return mapXnZY(this);
+ }
+ public Matrix4x3f mapXnZY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapXnZnY() {
+ return mapXnZnY(this);
+ }
+ public Matrix4x3f mapXnZnY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYXZ() {
+ return mapYXZ(this);
+ }
+ public Matrix4x3f mapYXZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYXnZ() {
+ return mapYXnZ(this);
+ }
+ public Matrix4x3f mapYXnZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYZX() {
+ return mapYZX(this);
+ }
+ public Matrix4x3f mapYZX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYZnX() {
+ return mapYZnX(this);
+ }
+ public Matrix4x3f mapYZnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYnXZ() {
+ return mapYnXZ(this);
+ }
+ public Matrix4x3f mapYnXZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYnXnZ() {
+ return mapYnXnZ(this);
+ }
+ public Matrix4x3f mapYnXnZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYnZX() {
+ return mapYnZX(this);
+ }
+ public Matrix4x3f mapYnZX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapYnZnX() {
+ return mapYnZnX(this);
+ }
+ public Matrix4x3f mapYnZnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m10)._m01(m11)._m02(m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZXY() {
+ return mapZXY(this);
+ }
+ public Matrix4x3f mapZXY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZXnY() {
+ return mapZXnY(this);
+ }
+ public Matrix4x3f mapZXnY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZYX() {
+ return mapZYX(this);
+ }
+ public Matrix4x3f mapZYX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZYnX() {
+ return mapZYnX(this);
+ }
+ public Matrix4x3f mapZYnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZnXY() {
+ return mapZnXY(this);
+ }
+ public Matrix4x3f mapZnXY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZnXnY() {
+ return mapZnXnY(this);
+ }
+ public Matrix4x3f mapZnXnY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZnYX() {
+ return mapZnYX(this);
+ }
+ public Matrix4x3f mapZnYX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapZnYnX() {
+ return mapZnYnX(this);
+ }
+ public Matrix4x3f mapZnYnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(m20)._m01(m21)._m02(m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXYnZ() {
+ return mapnXYnZ(this);
+ }
+ public Matrix4x3f mapnXYnZ(Matrix4x3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXZY() {
+ return mapnXZY(this);
+ }
+ public Matrix4x3f mapnXZY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXZnY() {
+ return mapnXZnY(this);
+ }
+ public Matrix4x3f mapnXZnY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m20)._m11(m21)._m12(m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXnYZ() {
+ return mapnXnYZ(this);
+ }
+ public Matrix4x3f mapnXnYZ(Matrix4x3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXnYnZ() {
+ return mapnXnYnZ(this);
+ }
+ public Matrix4x3f mapnXnYnZ(Matrix4x3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXnZY() {
+ return mapnXnZY(this);
+ }
+ public Matrix4x3f mapnXnZY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnXnZnY() {
+ return mapnXnZnY(this);
+ }
+ public Matrix4x3f mapnXnZnY(Matrix4x3f dest) {
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYXZ() {
+ return mapnYXZ(this);
+ }
+ public Matrix4x3f mapnYXZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYXnZ() {
+ return mapnYXnZ(this);
+ }
+ public Matrix4x3f mapnYXnZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m00)._m11(m01)._m12(m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYZX() {
+ return mapnYZX(this);
+ }
+ public Matrix4x3f mapnYZX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYZnX() {
+ return mapnYZnX(this);
+ }
+ public Matrix4x3f mapnYZnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(m20)._m11(m21)._m12(m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYnXZ() {
+ return mapnYnXZ(this);
+ }
+ public Matrix4x3f mapnYnXZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYnXnZ() {
+ return mapnYnXnZ(this);
+ }
+ public Matrix4x3f mapnYnXnZ(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYnZX() {
+ return mapnYnZX(this);
+ }
+ public Matrix4x3f mapnYnZX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnYnZnX() {
+ return mapnYnZnX(this);
+ }
+ public Matrix4x3f mapnYnZnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m10)._m01(-m11)._m02(-m12)._m10(-m20)._m11(-m21)._m12(-m22)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZXY() {
+ return mapnZXY(this);
+ }
+ public Matrix4x3f mapnZXY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZXnY() {
+ return mapnZXnY(this);
+ }
+ public Matrix4x3f mapnZXnY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m00)._m11(m01)._m12(m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZYX() {
+ return mapnZYX(this);
+ }
+ public Matrix4x3f mapnZYX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZYnX() {
+ return mapnZYnX(this);
+ }
+ public Matrix4x3f mapnZYnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(m10)._m11(m11)._m12(m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZnXY() {
+ return mapnZnXY(this);
+ }
+ public Matrix4x3f mapnZnXY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(m10)._m21(m11)._m22(m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZnXnY() {
+ return mapnZnXnY(this);
+ }
+ public Matrix4x3f mapnZnXnY(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ float m10 = this.m10, m11 = this.m11, m12 = this.m12;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m00)._m11(-m01)._m12(-m02)._m20(-m10)._m21(-m11)._m22(-m12)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZnYX() {
+ return mapnZnYX(this);
+ }
+ public Matrix4x3f mapnZnYX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m00)._m21(m01)._m22(m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f mapnZnYnX() {
+ return mapnZnYnX(this);
+ }
+ public Matrix4x3f mapnZnYnX(Matrix4x3f dest) {
+ float m00 = this.m00, m01 = this.m01, m02 = this.m02;
+ return dest._m00(-m20)._m01(-m21)._m02(-m22)._m10(-m10)._m11(-m11)._m12(-m12)._m20(-m00)._m21(-m01)._m22(-m02)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f negateX() {
+ return _m00(-m00)._m01(-m01)._m02(-m02)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ public Matrix4x3f negateX(Matrix4x3f dest) {
+ return dest._m00(-m00)._m01(-m01)._m02(-m02)._m10(m10)._m11(m11)._m12(m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f negateY() {
+ return _m10(-m10)._m11(-m11)._m12(-m12)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ public Matrix4x3f negateY(Matrix4x3f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(-m10)._m11(-m11)._m12(-m12)._m20(m20)._m21(m21)._m22(m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ *
+ * @return this
+ */
+ public Matrix4x3f negateZ() {
+ return _m20(-m20)._m21(-m21)._m22(-m22)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+ public Matrix4x3f negateZ(Matrix4x3f dest) {
+ return dest._m00(m00)._m01(m01)._m02(m02)._m10(m10)._m11(m11)._m12(m12)._m20(-m20)._m21(-m21)._m22(-m22)._m30(m30)._m31(m31)._m32(m32)._properties(properties & PROPERTY_ORTHONORMAL);
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(m00) && Math.isFinite(m01) && Math.isFinite(m02) &&
+ Math.isFinite(m10) && Math.isFinite(m11) && Math.isFinite(m12) &&
+ Math.isFinite(m20) && Math.isFinite(m21) && Math.isFinite(m22) &&
+ Math.isFinite(m30) && Math.isFinite(m31) && Math.isFinite(m32);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3fStack.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3fStack.java
new file mode 100644
index 000000000..dff3e5a5b
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3fStack.java
@@ -0,0 +1,186 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2018-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+/**
+ * A stack of many {@link Matrix4x3f} instances. This resembles the matrix stack known from legacy OpenGL.
+ *
+ * This {@link Matrix4x3fStack} class inherits from {@link Matrix4x3f}, so the current/top matrix is always the
+ * {@link Matrix4x3fStack}/{@link Matrix4x3f} itself. This affects all operations in {@link Matrix4x3f} that take
+ * another {@link Matrix4x3f} as parameter. If a {@link Matrix4x3fStack} is used as argument to those methods, the
+ * effective argument will always be the current matrix of the matrix stack.
+ *
+ * @author Kai Burjack
+ */
+public class Matrix4x3fStack extends Matrix4x3f {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The matrix stack as a non-growable array. The size of the stack must be specified in the {@link #Matrix4x3fStack(int) constructor}.
+ */
+ private Matrix4x3f[] mats;
+
+ /**
+ * The index of the "current" matrix within {@link #mats}.
+ */
+ private int curr;
+
+ /**
+ * Create a new {@link Matrix4x3fStack} of the given size.
+ *
+ * Initially the stack pointer is at zero and the current matrix is set to identity.
+ *
+ * @param stackSize
+ * the size of the stack. This must be at least 1, in which case the {@link Matrix4x3fStack} simply only consists of this
+ * {@link Matrix4x3f}
+ */
+ public Matrix4x3fStack(int stackSize) {
+ if (stackSize < 1) {
+ throw new IllegalArgumentException("stackSize must be >= 1"); //$NON-NLS-1$
+ }
+ mats = new Matrix4x3f[stackSize - 1];
+ // Allocate all matrices up front to keep the promise of being "allocation-free"
+ for (int i = 0; i < mats.length; i++) {
+ mats[i] = new Matrix4x3f();
+ }
+ }
+
+ /**
+ * Do not invoke manually! Only meant for serialization.
+ *
+ * Invoking this constructor from client code will result in an inconsistent state of the
+ * created {@link Matrix4x3fStack} instance.
+ */
+ public Matrix4x3fStack() {
+ /* Empty! */
+ }
+
+ /**
+ * Set the stack pointer to zero and set the current/bottom matrix to {@link #identity() identity}.
+ *
+ * @return this
+ */
+ public Matrix4x3fStack clear() {
+ curr = 0;
+ identity();
+ return this;
+ }
+
+ /**
+ * Increment the stack pointer by one and set the values of the new current matrix to the one directly below it.
+ *
+ * @return this
+ */
+ public Matrix4x3fStack pushMatrix() {
+ if (curr == mats.length) {
+ throw new IllegalStateException("max stack size of " + (curr + 1) + " reached"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ mats[curr++].set(this);
+ return this;
+ }
+
+ /**
+ * Decrement the stack pointer by one.
+ *
+ * This will effectively dispose of the current matrix.
+ *
+ * @return this
+ */
+ public Matrix4x3fStack popMatrix() {
+ if (curr == 0) {
+ throw new IllegalStateException("already at the bottom of the stack"); //$NON-NLS-1$
+ }
+ set(mats[--curr]);
+ return this;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + curr;
+ for (int i = 0; i < curr; i++) {
+ result = prime * result + mats[i].hashCode();
+ }
+ return result;
+ }
+
+ /*
+ * Contract between Matrix4x3f and Matrix4x3fStack:
+ *
+ * - Matrix4x3f.equals(Matrix4x3fStack) is true iff all the 12 matrix elements are equal
+ * - Matrix4x3fStack.equals(Matrix4x3f) is true iff all the 12 matrix elements are equal
+ * - Matrix4x3fStack.equals(Matrix4x3fStack) is true iff all 12 matrix elements are equal AND the matrix arrays as well as the stack pointer are equal
+ * - everything else is inequal
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (obj instanceof Matrix4x3fStack) {
+ Matrix4x3fStack other = (Matrix4x3fStack) obj;
+ if (curr != other.curr)
+ return false;
+ for (int i = 0; i < curr; i++) {
+ if (!mats[i].equals(other.mats[i]))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ super.writeExternal(out);
+ out.writeInt(curr);
+ for (int i = 0; i < curr; i++) {
+ out.writeObject(mats[i]);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException {
+ super.readExternal(in);
+ curr = in.readInt();
+ mats = new Matrix4x3fStack[curr];
+ for (int i = 0; i < curr; i++) {
+ Matrix4x3f m = new Matrix4x3f();
+ m.readExternal(in);
+ mats[i] = m;
+ }
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Matrix4x3fStack cloned = (Matrix4x3fStack) super.clone();
+ Matrix4x3f[] clonedMats = new Matrix4x3f[mats.length];
+ for (int i = 0; i < mats.length; i++)
+ clonedMats[i] = (Matrix4x3f) mats[i].clone();
+ cloned.mats = clonedMats;
+ return cloned;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3fc.java
new file mode 100644
index 000000000..d06253eb9
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Matrix4x3fc.java
@@ -0,0 +1,3544 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+
+/**
+ * Interface to a read-only view of a 4x3 matrix of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Matrix4x3fc {
+
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation x=-1
when using the identity matrix.
+ */
+ int PLANE_NX = 0;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation x=1
when using the identity matrix.
+ */
+ int PLANE_PX = 1;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation y=-1
when using the identity matrix.
+ */
+ int PLANE_NY = 2;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation y=1
when using the identity matrix.
+ */
+ int PLANE_PY = 3;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation z=-1
when using the identity matrix.
+ */
+ int PLANE_NZ = 4;
+ /**
+ * Argument to the first parameter of {@link #frustumPlane(int, Vector4f)}
+ * identifying the plane with equation z=1
when using the identity matrix.
+ */
+ int PLANE_PZ = 5;
+
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents the identity transformation.
+ */
+ byte PROPERTY_IDENTITY = 1<<2;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the matrix represents a pure translation transformation.
+ */
+ byte PROPERTY_TRANSLATION = 1<<3;
+ /**
+ * Bit returned by {@link #properties()} to indicate that the left 3x3 submatrix represents an orthogonal
+ * matrix (i.e. orthonormal basis).
+ */
+ byte PROPERTY_ORTHONORMAL = 1<<4;
+
+ /**
+ * @return the properties of the matrix
+ */
+ int properties();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m00();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m01();
+
+ /**
+ * Return the value of the matrix element at column 0 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m02();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m10();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m11();
+
+ /**
+ * Return the value of the matrix element at column 1 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m12();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m20();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m21();
+
+ /**
+ * Return the value of the matrix element at column 2 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m22();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 0.
+ *
+ * @return the value of the matrix element
+ */
+ float m30();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 1.
+ *
+ * @return the value of the matrix element
+ */
+ float m31();
+
+ /**
+ * Return the value of the matrix element at column 3 and row 2.
+ *
+ * @return the value of the matrix element
+ */
+ float m32();
+
+ /**
+ * Get the current values of this
matrix and store them into the upper 4x3 submatrix of dest
.
+ *
+ * The other elements of dest
will not be modified.
+ *
+ * @see Matrix4f#set4x3(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ Matrix4f get(Matrix4f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into the upper 4x3 submatrix of dest
.
+ *
+ * The other elements of dest
will not be modified.
+ *
+ * @see Matrix4d#set4x3(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination matrix
+ * @return dest
+ */
+ Matrix4d get(Matrix4d dest);
+
+ /**
+ * Multiply this matrix by the supplied right
matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3f mul(Matrix4x3fc right, Matrix4x3f dest);
+
+ /**
+ * Multiply this matrix, which is assumed to only contain a translation, by the supplied right
matrix and store the result in dest
.
+ *
+ * This method assumes that this
matrix only contains a translation.
+ *
+ * This method will not modify either the last row of this
or the last row of right
.
+ *
+ * If M
is this
matrix and R
the right
matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the right matrix will be applied first!
+ *
+ * @param right
+ * the right operand of the matrix multiplication
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3f mulTranslation(Matrix4x3fc right, Matrix4x3f dest);
+
+ /**
+ * Multiply this
orthographic projection matrix by the supplied view
matrix
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and V
the view
matrix,
+ * then the new matrix will be M * V
. So when transforming a
+ * vector v
with the new matrix by using M * V * v
, the
+ * transformation of the view
matrix will be applied first!
+ *
+ * @param view
+ * the matrix which to multiply this
with
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3f mulOrtho(Matrix4x3fc view, Matrix4x3f dest);
+
+ /**
+ * Multiply this
by the 4x3 matrix with the column vectors (rm00, rm01, rm02)
,
+ * (rm10, rm11, rm12)
, (rm20, rm21, rm22)
and (0, 0, 0)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the specified matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * transformation of the R
matrix will be applied first!
+ *
+ * @param rm00
+ * the value of the m00 element
+ * @param rm01
+ * the value of the m01 element
+ * @param rm02
+ * the value of the m02 element
+ * @param rm10
+ * the value of the m10 element
+ * @param rm11
+ * the value of the m11 element
+ * @param rm12
+ * the value of the m12 element
+ * @param rm20
+ * the value of the m20 element
+ * @param rm21
+ * the value of the m21 element
+ * @param rm22
+ * the value of the m22 element
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mul3x3(float rm00, float rm01, float rm02, float rm10, float rm11, float rm12, float rm20, float rm21, float rm22, Matrix4x3f dest);
+
+ /**
+ * Component-wise add this
and other
+ * by first multiplying each component of other
by otherFactor
,
+ * adding that to this
and storing the final result in dest
.
+ *
+ * The other components of dest
will be set to the ones of this
.
+ *
+ * The matrices this
and other
will not be changed.
+ *
+ * @param other
+ * the other matrix
+ * @param otherFactor
+ * the factor to multiply each of the other matrix's components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f fma(Matrix4x3fc other, float otherFactor, Matrix4x3f dest);
+
+ /**
+ * Component-wise add this
and other
and store the result in dest
.
+ *
+ * @param other
+ * the other addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f add(Matrix4x3fc other, Matrix4x3f dest);
+
+ /**
+ * Component-wise subtract subtrahend
from this
and store the result in dest
.
+ *
+ * @param subtrahend
+ * the subtrahend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f sub(Matrix4x3fc subtrahend, Matrix4x3f dest);
+
+ /**
+ * Component-wise multiply this
by other
and store the result in dest
.
+ *
+ * @param other
+ * the other matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mulComponentWise(Matrix4x3fc other, Matrix4x3f dest);
+
+ /**
+ * Return the determinant of this matrix.
+ *
+ * @return the determinant
+ */
+ float determinant();
+
+ /**
+ * Invert this matrix and write the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f invert(Matrix4x3f dest);
+
+ /**
+ * Invert this matrix and write the result as the top 4x3 matrix into dest
+ * and set all other values of dest
to identity..
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4f invert(Matrix4f dest);
+
+ /**
+ * Invert this
orthographic projection matrix and store the result into the given dest
.
+ *
+ * This method can be used to quickly obtain the inverse of an orthographic projection matrix.
+ *
+ * @param dest
+ * will hold the inverse of this
+ * @return dest
+ */
+ Matrix4x3f invertOrtho(Matrix4x3f dest);
+
+ /**
+ * Transpose only the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * All other matrix elements are left unchanged.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f transpose3x3(Matrix4x3f dest);
+
+ /**
+ * Transpose only the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f transpose3x3(Matrix3f dest);
+
+ /**
+ * Get only the translation components (m30, m31, m32)
of this matrix and store them in the given vector xyz
.
+ *
+ * @param dest
+ * will hold the translation components of this matrix
+ * @return dest
+ */
+ Vector3f getTranslation(Vector3f dest);
+
+ /**
+ * Get the scaling factors of this
matrix for the three base axes.
+ *
+ * @param dest
+ * will hold the scaling factors for x
, y
and z
+ * @return dest
+ */
+ Vector3f getScale(Vector3f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4x3f get(Matrix4x3f dest);
+
+ /**
+ * Get the current values of this
matrix and store them into
+ * dest
.
+ *
+ * @param dest
+ * the destination matrix
+ * @return the passed in destination
+ */
+ Matrix4x3d get(Matrix4x3d dest);
+
+ /**
+ * Get the rotational component of this
matrix and store the represented rotation
+ * into the given {@link AxisAngle4f}.
+ *
+ * @see AxisAngle4f#set(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination {@link AxisAngle4f}
+ * @return the passed in destination
+ */
+ AxisAngle4f getRotation(AxisAngle4f dest);
+
+ /**
+ * Get the rotational component of this
matrix and store the represented rotation
+ * into the given {@link AxisAngle4d}.
+ *
+ * @see AxisAngle4f#set(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination {@link AxisAngle4d}
+ * @return the passed in destination
+ */
+ AxisAngle4d getRotation(AxisAngle4d dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaternionf#setFromUnnormalized(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getUnnormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaternionf}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are normalized.
+ *
+ * @see Quaternionf#setFromNormalized(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination {@link Quaternionf}
+ * @return the passed in destination
+ */
+ Quaternionf getNormalizedRotation(Quaternionf dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are not normalized and
+ * thus allows to ignore any additional scaling factor that is applied to the matrix.
+ *
+ * @see Quaterniond#setFromUnnormalized(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getUnnormalizedRotation(Quaterniond dest);
+
+ /**
+ * Get the current values of this
matrix and store the represented rotation
+ * into the given {@link Quaterniond}.
+ *
+ * This method assumes that the first three column vectors of the left 3x3 submatrix are normalized.
+ *
+ * @see Quaterniond#setFromNormalized(Matrix4x3fc)
+ *
+ * @param dest
+ * the destination {@link Quaterniond}
+ * @return the passed in destination
+ */
+ Quaterniond getNormalizedRotation(Quaterniond dest);
+
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in column-major order at the given off-heap address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this matrix
+ * @return this
+ */
+ Matrix4x3fc getToAddress(long address);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get(float[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in column-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get(float[], int)}.
+ *
+ * @see #get(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get(float[] arr);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied array at the given offset,
+ * where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] get4x4(float[] arr, int offset);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied array,
+ * where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #get4x4(float[], int)}.
+ *
+ * @see #get4x4(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] get4x4(float[] arr);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x4(FloatBuffer buffer);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get4x4(int index, FloatBuffer buffer);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get4x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get4x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(ByteBuffer buffer);
+
+ /**
+ * Store a 4x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index, where the upper 4x3 submatrix is this
and the last row is (0, 0, 0, 1)
.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get4x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store the left 3x3 submatrix as 3x4 matrix in column-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #get3x4(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x4(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of the left 3x3 submatrix as 3x4 matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x4(FloatBuffer buffer);
+
+ /**
+ * Store the left 3x3 submatrix as 3x4 matrix in column-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of the left 3x3 submatrix as 3x4 matrix in column-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer get3x4(int index, FloatBuffer buffer);
+
+ /**
+ * Store the left 3x3 submatrix as 3x4 matrix in column-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #get3x4(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get3x4(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of the left 3x3 submatrix as 3x4 matrix in column-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x4(ByteBuffer buffer);
+
+ /**
+ * Store the left 3x3 submatrix as 3x4 matrix in column-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index, with the m03, m13 and m23 components being zero.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of the left 3x3 submatrix as 3x4 matrix in column-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer get3x4(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(FloatBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this matrix in row-major order
+ * @return the passed in buffer
+ */
+ FloatBuffer getTransposed(int index, FloatBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the matrix is stored, use {@link #getTransposed(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #getTransposed(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this matrix in row-major order at its current position
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(ByteBuffer buffer);
+
+ /**
+ * Store this matrix in row-major order into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this matrix in row-major order
+ * @return the passed in buffer
+ */
+ ByteBuffer getTransposed(int index, ByteBuffer buffer);
+
+ /**
+ * Store this matrix into the supplied float array in row-major order at the given offset.
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @param offset
+ * the offset into the array
+ * @return the passed in array
+ */
+ float[] getTransposed(float[] arr, int offset);
+
+ /**
+ * Store this matrix into the supplied float array in row-major order.
+ *
+ * In order to specify an explicit offset into the array, use the method {@link #getTransposed(float[], int)}.
+ *
+ * @see #getTransposed(float[], int)
+ *
+ * @param arr
+ * the array to write the matrix values into
+ * @return the passed in array
+ */
+ float[] getTransposed(float[] arr);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in that vector.
+ *
+ * @see Vector4f#mul(Matrix4x3fc)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector4f transform(Vector4f v);
+
+ /**
+ * Transform/multiply the given vector by this matrix and store the result in dest
.
+ *
+ * @see Vector4f#mul(Matrix4x3fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will contain the result
+ * @return dest
+ */
+ Vector4f transform(Vector4fc v, Vector4f dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction.
+ *
+ * In order to store the result in another vector, use {@link #transformPosition(Vector3fc, Vector3f)}.
+ *
+ * @see #transformPosition(Vector3fc, Vector3f)
+ * @see #transform(Vector4f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transformPosition(Vector3f v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=1, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 1.0, so it
+ * will represent a position/location in 3D-space rather than a direction.
+ *
+ * In order to store the result in the same vector, use {@link #transformPosition(Vector3f)}.
+ *
+ * @see #transformPosition(Vector3f)
+ * @see #transform(Vector4fc, Vector4f)
+ *
+ * @param v
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPosition(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in that vector.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in another vector, use {@link #transformDirection(Vector3fc, Vector3f)}.
+ *
+ * @see #transformDirection(Vector3fc, Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @return v
+ */
+ Vector3f transformDirection(Vector3f v);
+
+ /**
+ * Transform/multiply the given 3D-vector, as if it was a 4D-vector with w=0, by
+ * this matrix and store the result in dest
.
+ *
+ * The given 3D-vector is treated as a 4D-vector with its w-component being 0.0
, so it
+ * will represent a direction in 3D-space rather than a position. This method will therefore
+ * not take the translation part of the matrix into account.
+ *
+ * In order to store the result in the same vector, use {@link #transformDirection(Vector3f)}.
+ *
+ * @see #transformDirection(Vector3f)
+ *
+ * @param v
+ * the vector to transform and to hold the final result
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformDirection(Vector3fc v, Vector3f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given xyz.x
,
+ * xyz.y
and xyz.z
factors, respectively and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param xyz
+ * the factors of the x, y and z component, respectively
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f scale(Vector3fc xyz, Matrix4x3f dest);
+
+ /**
+ * Apply scaling to this matrix by uniformly scaling all base axes by the given xyz
factor
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * Individual scaling of all three axes can be applied using {@link #scale(float, float, float, Matrix4x3f)}.
+ *
+ * @see #scale(float, float, float, Matrix4x3f)
+ *
+ * @param xyz
+ * the factor for all components
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f scale(float xyz, Matrix4x3f dest);
+
+ /**
+ * Apply scaling to this matrix by by scaling the X axis by x
and the Y axis by y
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f scaleXY(float x, float y, Matrix4x3f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given sx,
+ * sy and sz factors while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(sx, sy, sz).translate(-ox, -oy, -oz)
+ *
+ * @param sx
+ * the scaling factor of the x component
+ * @param sy
+ * the scaling factor of the y component
+ * @param sz
+ * the scaling factor of the z component
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f scaleAround(float sx, float sy, float sz, float ox, float oy, float oz, Matrix4x3f dest);
+
+ /**
+ * Apply scaling to this matrix by scaling all three base axes by the given factor
+ * while using (ox, oy, oz)
as the scaling origin,
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * scaling will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).scale(factor).translate(-ox, -oy, -oz)
+ *
+ * @param factor
+ * the scaling factor for all three axes
+ * @param ox
+ * the x coordinate of the scaling origin
+ * @param oy
+ * the y coordinate of the scaling origin
+ * @param oz
+ * the z coordinate of the scaling origin
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4x3f scaleAround(float factor, float ox, float oy, float oz, Matrix4x3f dest);
+
+ /**
+ * Apply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
+ * , the scaling will be applied first!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f scale(float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Pre-multiply scaling to this
matrix by scaling the base axes by the given x,
+ * y and z factors and store the result in dest
.
+ *
+ * If M
is this
matrix and S
the scaling matrix,
+ * then the new matrix will be S * M
. So when transforming a
+ * vector v
with the new matrix by using S * M * v
+ * , the scaling will be applied last!
+ *
+ * @param x
+ * the factor of the x component
+ * @param y
+ * the factor of the y component
+ * @param z
+ * the factor of the z component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f scaleLocal(float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Apply rotation about the X axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateX(float ang, Matrix4x3f dest);
+
+ /**
+ * Apply rotation about the Y axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateY(float ang, Matrix4x3f dest);
+
+ /**
+ * Apply rotation about the Z axis to this matrix by rotating the given amount of radians
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateZ(float ang, Matrix4x3f dest);
+
+ /**
+ * Apply rotation of angleX
radians about the X axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateXYZ(float angleX, float angleY, float angleZ, Matrix4x3f dest);
+
+ /**
+ * Apply rotation of angleZ
radians about the Z axis, followed by a rotation of angleY
radians about the Y axis and
+ * followed by a rotation of angleX
radians about the X axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateZYX(float angleZ, float angleY, float angleX, Matrix4x3f dest);
+
+ /**
+ * Apply rotation of angleY
radians about the Y axis, followed by a rotation of angleX
radians about the X axis and
+ * followed by a rotation of angleZ
radians about the Z axis and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * @param angleY
+ * the angle to rotate about Y
+ * @param angleX
+ * the angle to rotate about X
+ * @param angleZ
+ * the angle to rotate about Z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateYXZ(float angleY, float angleX, float angleZ, Matrix4x3f dest);
+
+ /**
+ * Apply rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotate(float ang, float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Apply rotation to this matrix, which is assumed to only contain a translation, by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateTranslation(float ang, float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix while using (ox, oy, oz)
as the rotation origin,
+ * and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * This method is equivalent to calling: translate(ox, oy, oz, dest).rotate(quat).translate(-ox, -oy, -oz)
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param ox
+ * the x coordinate of the rotation origin
+ * @param oy
+ * the y coordinate of the rotation origin
+ * @param oz
+ * the z coordinate of the rotation origin
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateAround(Quaternionfc quat, float ox, float oy, float oz, Matrix4x3f dest);
+
+ /**
+ * Pre-multiply a rotation to this matrix by rotating the given amount of radians
+ * about the specified (x, y, z)
axis and store the result in dest
.
+ *
+ * The axis described by the three components needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and R
the rotation matrix,
+ * then the new matrix will be R * M
. So when transforming a
+ * vector v
with the new matrix by using R * M * v
, the
+ * rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param ang
+ * the angle in radians
+ * @param x
+ * the x component of the axis
+ * @param y
+ * the y component of the axis
+ * @param z
+ * the z component of the axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateLocal(float ang, float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f translate(Vector3fc offset, Matrix4x3f dest);
+
+ /**
+ * Apply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be M * T
. So when
+ * transforming a vector v
with the new matrix by using
+ * M * T * v
, the translation will be applied first!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f translate(float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param offset
+ * the number of units in x, y and z by which to translate
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f translateLocal(Vector3fc offset, Matrix4x3f dest);
+
+ /**
+ * Pre-multiply a translation to this matrix by translating by the given number of
+ * units in x, y and z and store the result in dest
.
+ *
+ * If M
is this
matrix and T
the translation
+ * matrix, then the new matrix will be T * M
. So when
+ * transforming a vector v
with the new matrix by using
+ * T * M * v
, the translation will be applied last!
+ *
+ * @param x
+ * the offset to translate in x
+ * @param y
+ * the offset to translate in y
+ * @param z
+ * the offset to translate in z
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f translateLocal(float x, float y, float z, Matrix4x3f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f ortho(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4x3f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordiante system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f orthoLH(float left, float right, float bottom, float top, float zNear, float zFar, Matrix4x3f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, boolean, Matrix4x3f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4x3f orthoSymmetric(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a right-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4x3f) ortho()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f orthoSymmetric(float width, float height, float zNear, float zFar, Matrix4x3f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using the given NDC z range to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, boolean, Matrix4x3f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @param zZeroToOne
+ * whether to use Vulkan's and Direct3D's NDC z range of [0..+1]
when true
+ * or whether to use OpenGL's NDC z range of [-1..+1]
when false
+ * @return dest
+ */
+ Matrix4x3f orthoSymmetricLH(float width, float height, float zNear, float zFar, boolean zZeroToOne, Matrix4x3f dest);
+
+ /**
+ * Apply a symmetric orthographic projection transformation for a left-handed coordinate system
+ * using OpenGL's NDC z range of [-1..+1]
to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4x3f) orthoLH()} with
+ * left=-width/2
, right=+width/2
, bottom=-height/2
and top=+height/2
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @param width
+ * the distance between the right and left frustum edges
+ * @param height
+ * the distance between the top and bottom frustum edges
+ * @param zNear
+ * near clipping plane distance
+ * @param zFar
+ * far clipping plane distance
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f orthoSymmetricLH(float width, float height, float zNear, float zFar, Matrix4x3f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a right-handed coordinate system to this matrix
+ * and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #ortho(float, float, float, float, float, float, Matrix4x3f) ortho()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #ortho(float, float, float, float, float, float, Matrix4x3f)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f ortho2D(float left, float right, float bottom, float top, Matrix4x3f dest);
+
+ /**
+ * Apply an orthographic projection transformation for a left-handed coordinate system to this matrix and store the result in dest
.
+ *
+ * This method is equivalent to calling {@link #orthoLH(float, float, float, float, float, float, Matrix4x3f) orthoLH()} with
+ * zNear=-1
and zFar=+1
.
+ *
+ * If M
is this
matrix and O
the orthographic projection matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * orthographic projection transformation will be applied first!
+ *
+ * Reference: http://www.songho.ca
+ *
+ * @see #orthoLH(float, float, float, float, float, float, Matrix4x3f)
+ *
+ * @param left
+ * the distance from the center to the left frustum edge
+ * @param right
+ * the distance from the center to the right frustum edge
+ * @param bottom
+ * the distance from the center to the bottom frustum edge
+ * @param top
+ * the distance from the center to the top frustum edge
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f ortho2DLH(float left, float right, float bottom, float top, Matrix4x3f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(Vector3fc, Vector3fc, Vector3fc, Matrix4x3f) lookAt}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAlong(float, float, float, float, float, float, Matrix4x3f)
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc, Matrix4x3f)
+ *
+ * @param dir
+ * the direction in space to look along
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lookAlong(Vector3fc dir, Vector3fc up, Matrix4x3f dest);
+
+ /**
+ * Apply a rotation transformation to this matrix to make -z
point along dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookalong rotation matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
, the
+ * lookalong rotation transformation will be applied first!
+ *
+ * This is equivalent to calling
+ * {@link #lookAt(float, float, float, float, float, float, float, float, float, Matrix4x3f) lookAt()}
+ * with eye = (0, 0, 0)
and center = dir
.
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float, Matrix4x3f)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4x3f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(float, float, float, float, float, float, float, float, float, Matrix4x3f)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lookAt(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4x3f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a right-handed coordinate system,
+ * that aligns -z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAt(Vector3fc, Vector3fc, Vector3fc, Matrix4x3f)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ, Matrix4x3f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(float, float, float, float, float, float, float, float, float, Matrix4x3f)
+ *
+ * @param eye
+ * the position of the camera
+ * @param center
+ * the point in space to look at
+ * @param up
+ * the direction of 'up'
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lookAtLH(Vector3fc eye, Vector3fc center, Vector3fc up, Matrix4x3f dest);
+
+ /**
+ * Apply a "lookat" transformation to this matrix for a left-handed coordinate system,
+ * that aligns +z
with center - eye
and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * @see #lookAtLH(Vector3fc, Vector3fc, Vector3fc, Matrix4x3f)
+ *
+ * @param eyeX
+ * the x-coordinate of the eye/camera location
+ * @param eyeY
+ * the y-coordinate of the eye/camera location
+ * @param eyeZ
+ * the z-coordinate of the eye/camera location
+ * @param centerX
+ * the x-coordinate of the point to look at
+ * @param centerY
+ * the y-coordinate of the point to look at
+ * @param centerZ
+ * the z-coordinate of the point to look at
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lookAtLH(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ, Matrix4x3f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotate(Quaternionfc quat, Matrix4x3f dest);
+
+ /**
+ * Apply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix, which is assumed to only contain a translation, and store
+ * the result in dest
.
+ *
+ * This method assumes this
to only contain a translation.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be M * Q
. So when transforming a
+ * vector v
with the new matrix by using M * Q * v
,
+ * the quaternion rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateTranslation(Quaternionfc quat, Matrix4x3f dest);
+
+ /**
+ * Pre-multiply the rotation - and possibly scaling - transformation of the given {@link Quaternionfc} to this matrix and store
+ * the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and Q
the rotation matrix obtained from the given quaternion,
+ * then the new matrix will be Q * M
. So when transforming a
+ * vector v
with the new matrix by using Q * M * v
,
+ * the quaternion rotation will be applied last!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @param quat
+ * the {@link Quaternionfc}
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateLocal(Quaternionfc quat, Matrix4x3f dest);
+
+ /**
+ * Apply a rotation transformation, rotating about the given {@link AxisAngle4f} and store the result in dest
.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given {@link AxisAngle4f},
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the {@link AxisAngle4f} rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float, Matrix4x3f)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} (needs to be {@link AxisAngle4f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotate(AxisAngle4f axisAngle, Matrix4x3f dest);
+
+ /**
+ * Apply a rotation transformation, rotating the given radians about the specified axis and store the result in dest
.
+ *
+ * The axis described by the axis
vector needs to be a unit vector.
+ *
+ * When used with a right-handed coordinate system, the produced rotation will rotate a vector
+ * counter-clockwise around the rotation axis, when viewing along the negative axis direction towards the origin.
+ * When used with a left-handed coordinate system, the rotation is clockwise.
+ *
+ * If M
is this
matrix and A
the rotation matrix obtained from the given axis-angle,
+ * then the new matrix will be M * A
. So when transforming a
+ * vector v
with the new matrix by using M * A * v
,
+ * the axis-angle rotation will be applied first!
+ *
+ * Reference: http://en.wikipedia.org
+ *
+ * @see #rotate(float, float, float, float, Matrix4x3f)
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis (needs to be {@link Vector3f#normalize() normalized})
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotate(float angle, Vector3fc axis, Matrix4x3f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the equation x*a + y*b + z*c + d = 0
and store the result in dest
.
+ *
+ * The vector (a, b, c)
must be a unit vector.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * Reference: msdn.microsoft.com
+ *
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f reflect(float a, float b, float c, float d, Matrix4x3f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param nx
+ * the x-coordinate of the plane normal
+ * @param ny
+ * the y-coordinate of the plane normal
+ * @param nz
+ * the z-coordinate of the plane normal
+ * @param px
+ * the x-coordinate of a point on the plane
+ * @param py
+ * the y-coordinate of a point on the plane
+ * @param pz
+ * the z-coordinate of a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f reflect(float nx, float ny, float nz, float px, float py, float pz, Matrix4x3f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about a plane
+ * specified via the plane orientation and a point on the plane, and store the result in dest
.
+ *
+ * This method can be used to build a reflection transformation based on the orientation of a mirror object in the scene.
+ * It is assumed that the default mirror plane's normal is (0, 0, 1)
. So, if the given {@link Quaternionfc} is
+ * the identity (does not apply any additional rotation), the reflection plane will be z=0
, offset by the given point
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param orientation
+ * the plane orientation relative to an implied normal vector of (0, 0, 1)
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f reflect(Quaternionfc orientation, Vector3fc point, Matrix4x3f dest);
+
+ /**
+ * Apply a mirror/reflection transformation to this matrix that reflects about the given plane
+ * specified via the plane normal and a point on the plane, and store the result in dest
.
+ *
+ * If M
is this
matrix and R
the reflection matrix,
+ * then the new matrix will be M * R
. So when transforming a
+ * vector v
with the new matrix by using M * R * v
, the
+ * reflection will be applied first!
+ *
+ * @param normal
+ * the plane normal
+ * @param point
+ * a point on the plane
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f reflect(Vector3fc normal, Vector3fc point, Matrix4x3f dest);
+
+ /**
+ * Get the row at the given row
index, starting with 0
.
+ *
+ * @param row
+ * the row index in [0..2]
+ * @param dest
+ * will hold the row components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if row
is not in [0..2]
+ */
+ Vector4f getRow(int row, Vector4f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Get the column at the given column
index, starting with 0
.
+ *
+ * @param column
+ * the column index in [0..2]
+ * @param dest
+ * will hold the column components
+ * @return the passed in destination
+ * @throws IndexOutOfBoundsException if column
is not in [0..2]
+ */
+ Vector3f getColumn(int column, Vector3f dest) throws IndexOutOfBoundsException;
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
+ * and store it into the left 3x3 submatrix of dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f normal(Matrix4x3f dest);
+
+ /**
+ * Compute a normal matrix from the left 3x3 submatrix of this
and store it into dest
.
+ *
+ * The normal matrix of m
is the transpose of the inverse of m
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f normal(Matrix3f dest);
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f cofactor3x3(Matrix3f dest);
+
+ /**
+ * Compute the cofactor matrix of the left 3x3 submatrix of this
+ * and store it into dest
.
+ * All other values of dest
will be set to identity.
+ *
+ * The cofactor matrix can be used instead of {@link #normal(Matrix4x3f)} to transform normals
+ * when the orientation of the normals with respect to the surface should be preserved.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f cofactor3x3(Matrix4x3f dest);
+
+ /**
+ * Normalize the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f normalize3x3(Matrix4x3f dest);
+
+ /**
+ * Normalize the left 3x3 submatrix of this matrix and store the result in dest
.
+ *
+ * The resulting matrix will map unit vectors to unit vectors, though a pair of orthogonal input unit
+ * vectors need not be mapped to a pair of orthogonal output vectors if the original matrix was not orthogonal itself
+ * (i.e. had skewing).
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix3f normalize3x3(Matrix3f dest);
+
+ /**
+ * Calculate a frustum plane of this
matrix, which
+ * can be a projection matrix or a combined modelview-projection matrix, and store the result
+ * in the given dest
.
+ *
+ * Generally, this method computes the frustum plane in the local frame of
+ * any coordinate system that existed before this
+ * transformation was applied to it in order to yield homogeneous clipping space.
+ *
+ * The plane normal, which is (a, b, c)
, is directed "inwards" of the frustum.
+ * Any plane/point test using a*x + b*y + c*z + d
therefore will yield a result greater than zero
+ * if the point is within the frustum (i.e. at the positive side of the frustum plane).
+ *
+ * Reference:
+ * Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix
+ *
+ * @param which
+ * one of the six possible planes, given as numeric constants
+ * {@link #PLANE_NX}, {@link #PLANE_PX},
+ * {@link #PLANE_NY}, {@link #PLANE_PY},
+ * {@link #PLANE_NZ} and {@link #PLANE_PZ}
+ * @param dest
+ * will hold the computed plane equation.
+ * The plane equation will be normalized, meaning that (a, b, c)
will be a unit vector
+ * @return dest
+ */
+ Vector4f frustumPlane(int which, Vector4f dest);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).invert();
+ * inv.transformDirection(dir.set(0, 0, 1)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveZ(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f positiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Z
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Z
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).transpose();
+ * inv.transformDirection(dir.set(0, 0, 1)).normalize();
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f normalizedPositiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).invert();
+ * inv.transformDirection(dir.set(1, 0, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveX(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f positiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +X
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).transpose();
+ * inv.transformDirection(dir.set(1, 0, 0)).normalize();
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f normalizedPositiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
matrix is applied.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).invert();
+ * inv.transformDirection(dir.set(0, 1, 0)).normalize();
+ *
+ * If this
is already an orthogonal matrix, then consider using {@link #normalizedPositiveY(Vector3f)} instead.
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f positiveY(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the transformation represented by this
orthogonal matrix is applied.
+ * This method only produces correct results if this
is an orthogonal matrix.
+ *
+ * This method uses the rotation component of the left 3x3 submatrix to obtain the direction
+ * that is transformed to +Y
by this
matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).transpose();
+ * inv.transformDirection(dir.set(0, 1, 0)).normalize();
+ *
+ *
+ * Reference: http://www.euclideanspace.com
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f normalizedPositiveY(Vector3f dir);
+
+ /**
+ * Obtain the position that gets transformed to the origin by this
matrix.
+ * This can be used to get the position of the "camera" from a given view transformation matrix.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Matrix4x3f inv = new Matrix4x3f(this).invert();
+ * inv.transformPosition(origin.set(0, 0, 0));
+ *
+ *
+ * @param origin
+ * will hold the position transformed to the origin
+ * @return origin
+ */
+ Vector3f origin(Vector3f origin);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param light
+ * the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f shadow(Vector4fc light, float a, float b, float c, float d, Matrix4x3f dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane specified via the general plane equation
+ * x*a + y*b + z*c + d = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * Reference: ftp.sgi.com
+ *
+ * @param lightX
+ * the x-component of the light's vector
+ * @param lightY
+ * the y-component of the light's vector
+ * @param lightZ
+ * the z-component of the light's vector
+ * @param lightW
+ * the w-component of the light's vector
+ * @param a
+ * the x factor in the plane equation
+ * @param b
+ * the y factor in the plane equation
+ * @param c
+ * the z factor in the plane equation
+ * @param d
+ * the constant in the plane equation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f shadow(float lightX, float lightY, float lightZ, float lightW, float a, float b, float c, float d, Matrix4x3f dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction light
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If light.w
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param light
+ * the light's vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f shadow(Vector4fc light, Matrix4x3fc planeTransform, Matrix4x3f dest);
+
+ /**
+ * Apply a projection transformation to this matrix that projects onto the plane with the general plane equation
+ * y = 0
as if casting a shadow from a given light position/direction (lightX, lightY, lightZ, lightW)
+ * and store the result in dest
.
+ *
+ * Before the shadow projection is applied, the plane is transformed via the specified planeTransformation
.
+ *
+ * If lightW
is 0.0
the light is being treated as a directional light; if it is 1.0
it is a point light.
+ *
+ * If M
is this
matrix and S
the shadow matrix,
+ * then the new matrix will be M * S
. So when transforming a
+ * vector v
with the new matrix by using M * S * v
, the
+ * shadow projection will be applied first!
+ *
+ * @param lightX
+ * the x-component of the light vector
+ * @param lightY
+ * the y-component of the light vector
+ * @param lightZ
+ * the z-component of the light vector
+ * @param lightW
+ * the w-component of the light vector
+ * @param planeTransform
+ * the transformation to transform the implied plane y = 0
before applying the projection
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f shadow(float lightX, float lightY, float lightZ, float lightW, Matrix4x3fc planeTransform, Matrix4x3f dest);
+
+ /**
+ * Apply a picking transformation to this matrix using the given window coordinates (x, y)
as the pick center
+ * and the given (width, height)
as the size of the picking region in window coordinates, and store the result
+ * in dest
.
+ *
+ * @param x
+ * the x coordinate of the picking region center in window coordinates
+ * @param y
+ * the y coordinate of the picking region center in window coordinates
+ * @param width
+ * the width of the picking region in window coordinates
+ * @param height
+ * the height of the picking region in window coordinates
+ * @param viewport
+ * the viewport described by [x, y, width, height]
+ * @param dest
+ * the destination matrix, which will hold the result
+ * @return dest
+ */
+ Matrix4x3f pick(float x, float y, float width, float height, int[] viewport, Matrix4x3f dest);
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center (centerX, centerY, centerZ)
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius, dest).rotateX(angleX).rotateY(angleY).translate(-centerX, -centerY, -centerZ)
+ *
+ * @param radius
+ * the arcball radius
+ * @param centerX
+ * the x coordinate of the center position of the arcball
+ * @param centerY
+ * the y coordinate of the center position of the arcball
+ * @param centerZ
+ * the z coordinate of the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f arcball(float radius, float centerX, float centerY, float centerZ, float angleX, float angleY, Matrix4x3f dest);
+
+ /**
+ * Apply an arcball view transformation to this matrix with the given radius
and center
+ * position of the arcball and the specified X and Y rotation angles, and store the result in dest
.
+ *
+ * This method is equivalent to calling: translate(0, 0, -radius).rotateX(angleX).rotateY(angleY).translate(-center.x, -center.y, -center.z)
+ *
+ * @param radius
+ * the arcball radius
+ * @param center
+ * the center position of the arcball
+ * @param angleX
+ * the rotation angle around the X axis in radians
+ * @param angleY
+ * the rotation angle around the Y axis in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f arcball(float radius, Vector3fc center, float angleX, float angleY, Matrix4x3f dest);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner (minX, minY, minZ)
and maximum corner (maxX, maxY, maxZ)
+ * by this
matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * Reference: http://dev.theomader.com
+ *
+ * @param minX
+ * the x coordinate of the minimum corner of the axis-aligned box
+ * @param minY
+ * the y coordinate of the minimum corner of the axis-aligned box
+ * @param minZ
+ * the z coordinate of the minimum corner of the axis-aligned box
+ * @param maxX
+ * the x coordinate of the maximum corner of the axis-aligned box
+ * @param maxY
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param maxZ
+ * the y coordinate of the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4x3f transformAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, Vector3f outMin, Vector3f outMax);
+
+ /**
+ * Transform the axis-aligned box given as the minimum corner min
and maximum corner max
+ * by this
matrix and compute the axis-aligned box of the result whose minimum corner is stored in outMin
+ * and maximum corner stored in outMax
.
+ *
+ * @param min
+ * the minimum corner of the axis-aligned box
+ * @param max
+ * the maximum corner of the axis-aligned box
+ * @param outMin
+ * will hold the minimum corner of the resulting axis-aligned box
+ * @param outMax
+ * will hold the maximum corner of the resulting axis-aligned box
+ * @return this
+ */
+ Matrix4x3f transformAab(Vector3fc min, Vector3fc max, Vector3f outMin, Vector3f outMax);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other matrix
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f lerp(Matrix4x3fc other, float t, Matrix4x3f dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with dir
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3f().lookAt(new Vector3f(), new Vector3f(dir).negate(), up).invert(), dest)
+ *
+ * @see #rotateTowards(float, float, float, float, float, float, Matrix4x3f)
+ *
+ * @param dir
+ * the direction to rotate towards
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateTowards(Vector3fc dir, Vector3fc up, Matrix4x3f dest);
+
+ /**
+ * Apply a model transformation to this matrix for a right-handed coordinate system,
+ * that aligns the local +Z
axis with (dirX, dirY, dirZ)
+ * and store the result in dest
.
+ *
+ * If M
is this
matrix and L
the lookat matrix,
+ * then the new matrix will be M * L
. So when transforming a
+ * vector v
with the new matrix by using M * L * v
,
+ * the lookat transformation will be applied first!
+ *
+ * This method is equivalent to calling: mul(new Matrix4x3f().lookAt(0, 0, 0, -dirX, -dirY, -dirZ, upX, upY, upZ).invert(), dest)
+ *
+ * @see #rotateTowards(Vector3fc, Vector3fc, Matrix4x3f)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to rotate towards
+ * @param dirY
+ * the y-coordinate of the direction to rotate towards
+ * @param dirZ
+ * the z-coordinate of the direction to rotate towards
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f rotateTowards(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Matrix4x3f dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the left 3x3 submatrix of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order X * Y * Z
to obtain the identical matrix.
+ * This means that calling {@link Matrix4x3fc#rotateXYZ(float, float, float, Matrix4x3f)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4x3f m = ...; // <- matrix only representing rotation
+ * Matrix4x3f n = new Matrix4x3f();
+ * n.rotateXYZ(m.getEulerAnglesXYZ(new Vector3f()));
+ *
+ *
+ * Reference: http://nghiaho.com/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3f getEulerAnglesXYZ(Vector3f dest);
+
+ /**
+ * Extract the Euler angles from the rotation represented by the left 3x3 submatrix of this
+ * and store the extracted Euler angles in dest
.
+ *
+ * This method assumes that the left 3x3 submatrix of this
only represents a rotation without scaling.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * Note that the returned Euler angles must be applied in the order Z * Y * X
to obtain the identical matrix.
+ * This means that calling {@link Matrix4x3fc#rotateZYX(float, float, float, Matrix4x3f)} using the obtained Euler angles will yield
+ * the same rotation as the original matrix from which the Euler angles were obtained, so in the below code the matrix
+ * m2
should be identical to m
(disregarding possible floating-point inaccuracies).
+ *
+ * Matrix4x3f m = ...; // <- matrix only representing rotation
+ * Matrix4x3f n = new Matrix4x3f();
+ * n.rotateZYX(m.getEulerAnglesZYX(new Vector3f()));
+ *
+ *
+ * Reference: http://nghiaho.com/
+ *
+ * @param dest
+ * will hold the extracted Euler angles
+ * @return dest
+ */
+ Vector3f getEulerAnglesZYX(Vector3f dest);
+
+ /**
+ * Apply an oblique projection transformation to this matrix with the given values for a
and
+ * b
and store the result in dest
.
+ *
+ * If M
is this
matrix and O
the oblique transformation matrix,
+ * then the new matrix will be M * O
. So when transforming a
+ * vector v
with the new matrix by using M * O * v
, the
+ * oblique transformation will be applied first!
+ *
+ * The oblique transformation is defined as:
+ *
+ * x' = x + a*z
+ * y' = y + a*z
+ * z' = z
+ *
+ * or in matrix form:
+ *
+ * 1 0 a 0
+ * 0 1 b 0
+ * 0 0 1 0
+ *
+ *
+ * @param a
+ * the value for the z factor that applies to x
+ * @param b
+ * the value for the z factor that applies to y
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f obliqueZ(float a, float b, Matrix4x3f dest);
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector up
, and store the result in dest
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from calling
+ * {@link Matrix4f#setLookAt(Vector3fc, Vector3fc, Vector3fc)} with the current
+ * local origin of this matrix (as obtained by {@link #origin(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector up
.
+ *
+ * @param up
+ * the up vector
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4x3f withLookAtUp(Vector3fc up, Matrix4x3f dest);
+
+ /**
+ * Apply a transformation to this matrix to ensure that the local Y axis (as obtained by {@link #positiveY(Vector3f)})
+ * will be coplanar to the plane spanned by the local Z axis (as obtained by {@link #positiveZ(Vector3f)}) and the
+ * given vector (upX, upY, upZ)
, and store the result in dest
.
+ *
+ * This effectively ensures that the resulting matrix will be equal to the one obtained from calling
+ * {@link Matrix4f#setLookAt(float, float, float, float, float, float, float, float, float)} called with the current
+ * local origin of this matrix (as obtained by {@link #origin(Vector3f)}), the sum of this position and the
+ * negated local Z axis as well as the given vector (upX, upY, upZ)
.
+ *
+ * @param upX
+ * the x coordinate of the up vector
+ * @param upY
+ * the y coordinate of the up vector
+ * @param upZ
+ * the z coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return this
+ */
+ Matrix4x3f withLookAtUp(float upX, float upY, float upZ, Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapXZY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapXZnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapXnYnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapXnZY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapXnZnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYXZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYXnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYZX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYZnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYnXZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYnXnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYnZX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapYnZnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZXY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZXnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZYX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZYnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZnXY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZnXnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZnYX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * 1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapZnYnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXYnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXZY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXZnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXnYZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 -1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXnYnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXnZY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 0 -1 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnXnZnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYXZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYXnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYZX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYZnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYnXZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * -1 0 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYnXnZ(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYnZX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * -1 0 0 0
+ * 0 -1 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnYnZnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZXY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZXnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZYX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZYnX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZnXY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 -1 0 0
+ * 0 0 -1 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZnXnY(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZnYX(Matrix4x3f dest);
+ /**
+ * Multiply this
by the matrix
+ *
+ * 0 0 -1 0
+ * 0 -1 0 0
+ * -1 0 0 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f mapnZnYnX(Matrix4x3f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * -1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f negateX(Matrix4x3f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 -1 0 0
+ * 0 0 1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f negateY(Matrix4x3f dest);
+
+ /**
+ * Multiply this
by the matrix
+ *
+ * 1 0 0 0
+ * 0 1 0 0
+ * 0 0 -1 0
+ *
+ * and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Matrix4x3f negateZ(Matrix4x3f dest);
+
+ /**
+ * Compare the matrix elements of this
matrix with the given matrix using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param m
+ * the other matrix
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the matrix elements are equal; false
otherwise
+ */
+ boolean equals(Matrix4x3fc m, float delta);
+
+ /**
+ * Determine whether all matrix elements are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/MemUtil.java b/src/main/java/com/jozufozu/flywheel/repack/joml/MemUtil.java
new file mode 100644
index 000000000..c249ff070
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/MemUtil.java
@@ -0,0 +1,5572 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.lang.reflect.Field;
+import java.nio.*;
+
+/**
+ * Helper class to do efficient memory operations on all JOML objects, NIO buffers and primitive arrays.
+ * This class is used internally throughout JOML, is undocumented and is subject to change.
+ * Use with extreme caution!
+ *
+ * @author The LWJGL authors
+ * @author Kai Burjack
+ */
+abstract class MemUtil {
+ public static final MemUtil INSTANCE = createInstance();
+ private static MemUtil createInstance() {
+ MemUtil accessor;
+ try {
+ if (Options.NO_UNSAFE && Options.FORCE_UNSAFE)
+ throw new ConfigurationException("Cannot enable both -Djoml.nounsafe and -Djoml.forceUnsafe", null);
+ else if (Options.NO_UNSAFE)
+ accessor = new MemUtilNIO();
+ else
+ accessor = new MemUtilUnsafe();
+ } catch (Throwable e) {
+ if (Options.FORCE_UNSAFE)
+ throw new ConfigurationException("Unsafe is not supported but its use was forced via -Djoml.forceUnsafe", e);
+ accessor = new MemUtilNIO();
+ }
+ return accessor;
+ }
+
+ public abstract void put(Matrix4f m, int offset, FloatBuffer dest);
+ public abstract void put(Matrix4f m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix4x3f m, int offset, FloatBuffer dest);
+ public abstract void put(Matrix4x3f m, int offset, ByteBuffer dest);
+ public abstract void put4x4(Matrix4x3f m, int offset, FloatBuffer dest);
+ public abstract void put4x4(Matrix4x3f m, int offset, ByteBuffer dest);
+ public abstract void put4x4(Matrix4x3d m, int offset, DoubleBuffer dest);
+ public abstract void put4x4(Matrix4x3d m, int offset, ByteBuffer dest);
+ public abstract void put4x4(Matrix3x2f m, int offset, FloatBuffer dest);
+ public abstract void put4x4(Matrix3x2f m, int offset, ByteBuffer dest);
+ public abstract void put4x4(Matrix3x2d m, int offset, DoubleBuffer dest);
+ public abstract void put4x4(Matrix3x2d m, int offset, ByteBuffer dest);
+ public abstract void put3x3(Matrix3x2f m, int offset, FloatBuffer dest);
+ public abstract void put3x3(Matrix3x2f m, int offset, ByteBuffer dest);
+ public abstract void put3x3(Matrix3x2d m, int offset, DoubleBuffer dest);
+ public abstract void put3x3(Matrix3x2d m, int offset, ByteBuffer dest);
+ public abstract void put4x3(Matrix4f m, int offset, FloatBuffer dest);
+ public abstract void put4x3(Matrix4f m, int offset, ByteBuffer dest);
+ public abstract void put3x4(Matrix4f m, int offset, FloatBuffer dest);
+ public abstract void put3x4(Matrix4f m, int offset, ByteBuffer dest);
+ public abstract void put3x4(Matrix4x3f m, int offset, FloatBuffer dest);
+ public abstract void put3x4(Matrix4x3f m, int offset, ByteBuffer dest);
+ public abstract void put3x4(Matrix3f m, int offset, FloatBuffer dest);
+ public abstract void put3x4(Matrix3f m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix4f m, int offset, FloatBuffer dest);
+ public abstract void putTransposed(Matrix4f m, int offset, ByteBuffer dest);
+ public abstract void put4x3Transposed(Matrix4f m, int offset, FloatBuffer dest);
+ public abstract void put4x3Transposed(Matrix4f m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix4x3f m, int offset, FloatBuffer dest);
+ public abstract void putTransposed(Matrix4x3f m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix3f m, int offset, FloatBuffer dest);
+ public abstract void putTransposed(Matrix3f m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix2f m, int offset, FloatBuffer dest);
+ public abstract void putTransposed(Matrix2f m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix4d m, int offset, DoubleBuffer dest);
+ public abstract void put(Matrix4d m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix4x3d m, int offset, DoubleBuffer dest);
+ public abstract void put(Matrix4x3d m, int offset, ByteBuffer dest);
+ public abstract void putf(Matrix4d m, int offset, FloatBuffer dest);
+ public abstract void putf(Matrix4d m, int offset, ByteBuffer dest);
+ public abstract void putf(Matrix4x3d m, int offset, FloatBuffer dest);
+ public abstract void putf(Matrix4x3d m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix4d m, int offset, DoubleBuffer dest);
+ public abstract void putTransposed(Matrix4d m, int offset, ByteBuffer dest);
+ public abstract void put4x3Transposed(Matrix4d m, int offset, DoubleBuffer dest);
+ public abstract void put4x3Transposed(Matrix4d m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix4x3d m, int offset, DoubleBuffer dest);
+ public abstract void putTransposed(Matrix4x3d m, int offset, ByteBuffer dest);
+ public abstract void putTransposed(Matrix2d m, int offset, DoubleBuffer dest);
+ public abstract void putTransposed(Matrix2d m, int offset, ByteBuffer dest);
+ public abstract void putfTransposed(Matrix4d m, int offset, FloatBuffer dest);
+ public abstract void putfTransposed(Matrix4d m, int offset, ByteBuffer dest);
+ public abstract void putfTransposed(Matrix4x3d m, int offset, FloatBuffer dest);
+ public abstract void putfTransposed(Matrix4x3d m, int offset, ByteBuffer dest);
+ public abstract void putfTransposed(Matrix2d m, int offset, FloatBuffer dest);
+ public abstract void putfTransposed(Matrix2d m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix3f m, int offset, FloatBuffer dest);
+ public abstract void put(Matrix3f m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix3d m, int offset, DoubleBuffer dest);
+ public abstract void put(Matrix3d m, int offset, ByteBuffer dest);
+ public abstract void putf(Matrix3d m, int offset, FloatBuffer dest);
+ public abstract void putf(Matrix3d m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix3x2f m, int offset, FloatBuffer dest);
+ public abstract void put(Matrix3x2f m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix3x2d m, int offset, DoubleBuffer dest);
+ public abstract void put(Matrix3x2d m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix2f m, int offset, FloatBuffer dest);
+ public abstract void put(Matrix2f m, int offset, ByteBuffer dest);
+ public abstract void put(Matrix2d m, int offset, DoubleBuffer dest);
+ public abstract void put(Matrix2d m, int offset, ByteBuffer dest);
+ public abstract void putf(Matrix2d m, int offset, FloatBuffer dest);
+ public abstract void putf(Matrix2d m, int offset, ByteBuffer dest);
+ public abstract void put(Vector4d src, int offset, DoubleBuffer dest);
+ public abstract void put(Vector4d src, int offset, FloatBuffer dest);
+ public abstract void put(Vector4d src, int offset, ByteBuffer dest);
+ public abstract void putf(Vector4d src, int offset, ByteBuffer dest);
+ public abstract void put(Vector4f src, int offset, FloatBuffer dest);
+ public abstract void put(Vector4f src, int offset, ByteBuffer dest);
+ public abstract void put(Vector4i src, int offset, IntBuffer dest);
+ public abstract void put(Vector4i src, int offset, ByteBuffer dest);
+ public abstract void put(Vector3f src, int offset, FloatBuffer dest);
+ public abstract void put(Vector3f src, int offset, ByteBuffer dest);
+ public abstract void put(Vector3d src, int offset, DoubleBuffer dest);
+ public abstract void put(Vector3d src, int offset, FloatBuffer dest);
+ public abstract void put(Vector3d src, int offset, ByteBuffer dest);
+ public abstract void putf(Vector3d src, int offset, ByteBuffer dest);
+ public abstract void put(Vector3i src, int offset, IntBuffer dest);
+ public abstract void put(Vector3i src, int offset, ByteBuffer dest);
+ public abstract void put(Vector2f src, int offset, FloatBuffer dest);
+ public abstract void put(Vector2f src, int offset, ByteBuffer dest);
+ public abstract void put(Vector2d src, int offset, DoubleBuffer dest);
+ public abstract void put(Vector2d src, int offset, ByteBuffer dest);
+ public abstract void put(Vector2i src, int offset, IntBuffer dest);
+ public abstract void put(Vector2i src, int offset, ByteBuffer dest);
+ public abstract void get(Matrix4f m, int offset, FloatBuffer src);
+ public abstract void get(Matrix4f m, int offset, ByteBuffer src);
+ public abstract void getTransposed(Matrix4f m, int offset, FloatBuffer src);
+ public abstract void getTransposed(Matrix4f m, int offset, ByteBuffer src);
+ public abstract void get(Matrix4x3f m, int offset, FloatBuffer src);
+ public abstract void get(Matrix4x3f m, int offset, ByteBuffer src);
+ public abstract void get(Matrix4d m, int offset, DoubleBuffer src);
+ public abstract void get(Matrix4d m, int offset, ByteBuffer src);
+ public abstract void get(Matrix4x3d m, int offset, DoubleBuffer src);
+ public abstract void get(Matrix4x3d m, int offset, ByteBuffer src);
+ public abstract void getf(Matrix4d m, int offset, FloatBuffer src);
+ public abstract void getf(Matrix4d m, int offset, ByteBuffer src);
+ public abstract void getf(Matrix4x3d m, int offset, FloatBuffer src);
+ public abstract void getf(Matrix4x3d m, int offset, ByteBuffer src);
+ public abstract void get(Matrix3f m, int offset, FloatBuffer src);
+ public abstract void get(Matrix3f m, int offset, ByteBuffer src);
+ public abstract void get(Matrix3d m, int offset, DoubleBuffer src);
+ public abstract void get(Matrix3d m, int offset, ByteBuffer src);
+ public abstract void get(Matrix3x2f m, int offset, FloatBuffer src);
+ public abstract void get(Matrix3x2f m, int offset, ByteBuffer src);
+ public abstract void get(Matrix3x2d m, int offset, DoubleBuffer src);
+ public abstract void get(Matrix3x2d m, int offset, ByteBuffer src);
+ public abstract void getf(Matrix3d m, int offset, FloatBuffer src);
+ public abstract void getf(Matrix3d m, int offset, ByteBuffer src);
+ public abstract void get(Matrix2f m, int offset, FloatBuffer src);
+ public abstract void get(Matrix2f m, int offset, ByteBuffer src);
+ public abstract void get(Matrix2d m, int offset, DoubleBuffer src);
+ public abstract void get(Matrix2d m, int offset, ByteBuffer src);
+ public abstract void getf(Matrix2d m, int offset, FloatBuffer src);
+ public abstract void getf(Matrix2d m, int offset, ByteBuffer src);
+ public abstract void get(Vector4d dst, int offset, DoubleBuffer src);
+ public abstract void get(Vector4d dst, int offset, ByteBuffer src);
+ public abstract void get(Vector4f dst, int offset, FloatBuffer src);
+ public abstract void get(Vector4f dst, int offset, ByteBuffer src);
+ public abstract void get(Vector4i dst, int offset, IntBuffer src);
+ public abstract void get(Vector4i dst, int offset, ByteBuffer src);
+ public abstract void get(Vector3f dst, int offset, FloatBuffer src);
+ public abstract void get(Vector3f dst, int offset, ByteBuffer src);
+ public abstract void get(Vector3d dst, int offset, DoubleBuffer src);
+ public abstract void get(Vector3d dst, int offset, ByteBuffer src);
+ public abstract void get(Vector3i dst, int offset, IntBuffer src);
+ public abstract void get(Vector3i dst, int offset, ByteBuffer src);
+ public abstract void get(Vector2f dst, int offset, FloatBuffer src);
+ public abstract void get(Vector2f dst, int offset, ByteBuffer src);
+ public abstract void get(Vector2d dst, int offset, DoubleBuffer src);
+ public abstract void get(Vector2d dst, int offset, ByteBuffer src);
+ public abstract void get(Vector2i dst, int offset, IntBuffer src);
+ public abstract void get(Vector2i dst, int offset, ByteBuffer src);
+ public abstract void putMatrix3f(Quaternionf q, int position, ByteBuffer dest);
+ public abstract void putMatrix3f(Quaternionf q, int position, FloatBuffer dest);
+ public abstract void putMatrix4f(Quaternionf q, int position, ByteBuffer dest);
+ public abstract void putMatrix4f(Quaternionf q, int position, FloatBuffer dest);
+ public abstract void putMatrix4x3f(Quaternionf q, int position, ByteBuffer dest);
+ public abstract void putMatrix4x3f(Quaternionf q, int position, FloatBuffer dest);
+
+ public abstract float get(Matrix4f m, int column, int row);
+ public abstract Matrix4f set(Matrix4f m, int column, int row, float v);
+ public abstract double get(Matrix4d m, int column, int row);
+ public abstract Matrix4d set(Matrix4d m, int column, int row, double v);
+ public abstract float get(Matrix3f m, int column, int row);
+ public abstract Matrix3f set(Matrix3f m, int column, int row, float v);
+ public abstract double get(Matrix3d m, int column, int row);
+ public abstract Matrix3d set(Matrix3d m, int column, int row, double v);
+ public abstract Vector4f getColumn(Matrix4f m, int column, Vector4f dest);
+ public abstract Matrix4f setColumn(Vector4f v, int column, Matrix4f dest);
+ public abstract Matrix4f setColumn(Vector4fc v, int column, Matrix4f dest);
+ public abstract void copy(Matrix4f src, Matrix4f dest);
+ public abstract void copy(Matrix4x3f src, Matrix4x3f dest);
+ public abstract void copy(Matrix4f src, Matrix4x3f dest);
+ public abstract void copy(Matrix4x3f src, Matrix4f dest);
+ public abstract void copy(Matrix3f src, Matrix3f dest);
+ public abstract void copy(Matrix3f src, Matrix4f dest);
+ public abstract void copy(Matrix4f src, Matrix3f dest);
+ public abstract void copy(Matrix3f src, Matrix4x3f dest);
+ public abstract void copy(Matrix3x2f src, Matrix3x2f dest);
+ public abstract void copy(Matrix3x2d src, Matrix3x2d dest);
+ public abstract void copy(Matrix2f src, Matrix2f dest);
+ public abstract void copy(Matrix2d src, Matrix2d dest);
+ public abstract void copy(Matrix2f src, Matrix3f dest);
+ public abstract void copy(Matrix3f src, Matrix2f dest);
+ public abstract void copy(Matrix2f src, Matrix3x2f dest);
+ public abstract void copy(Matrix3x2f src, Matrix2f dest);
+ public abstract void copy(Matrix2d src, Matrix3d dest);
+ public abstract void copy(Matrix3d src, Matrix2d dest);
+ public abstract void copy(Matrix2d src, Matrix3x2d dest);
+ public abstract void copy(Matrix3x2d src, Matrix2d dest);
+ public abstract void copy3x3(Matrix4f src, Matrix4f dest);
+ public abstract void copy3x3(Matrix4x3f src, Matrix4x3f dest);
+ public abstract void copy3x3(Matrix3f src, Matrix4x3f dest);
+ public abstract void copy3x3(Matrix3f src, Matrix4f dest);
+ public abstract void copy4x3(Matrix4f src, Matrix4f dest);
+ public abstract void copy4x3(Matrix4x3f src, Matrix4f dest);
+ public abstract void copy(float[] arr, int off, Matrix4f dest);
+ public abstract void copyTransposed(float[] arr, int off, Matrix4f dest);
+ public abstract void copy(float[] arr, int off, Matrix3f dest);
+ public abstract void copy(float[] arr, int off, Matrix4x3f dest);
+ public abstract void copy(float[] arr, int off, Matrix3x2f dest);
+ public abstract void copy(double[] arr, int off, Matrix3x2d dest);
+ public abstract void copy(float[] arr, int off, Matrix2f dest);
+ public abstract void copy(double[] arr, int off, Matrix2d dest);
+ public abstract void copy(Matrix4f src, float[] dest, int off);
+ public abstract void copy(Matrix3f src, float[] dest, int off);
+ public abstract void copy(Matrix4x3f src, float[] dest, int off);
+ public abstract void copy(Matrix3x2f src, float[] dest, int off);
+ public abstract void copy(Matrix3x2d src, double[] dest, int off);
+ public abstract void copy(Matrix2f src, float[] dest, int off);
+ public abstract void copy(Matrix2d src, double[] dest, int off);
+ public abstract void copy4x4(Matrix4x3f src, float[] dest, int off);
+ public abstract void copy4x4(Matrix4x3d src, float[] dest, int off);
+ public abstract void copy4x4(Matrix4x3d src, double[] dest, int off);
+ public abstract void copy4x4(Matrix3x2f src, float[] dest, int off);
+ public abstract void copy4x4(Matrix3x2d src, double[] dest, int off);
+ public abstract void copy3x3(Matrix3x2f src, float[] dest, int off);
+ public abstract void copy3x3(Matrix3x2d src, double[] dest, int off);
+ public abstract void identity(Matrix4f dest);
+ public abstract void identity(Matrix4x3f dest);
+ public abstract void identity(Matrix3f dest);
+ public abstract void identity(Matrix3x2f dest);
+ public abstract void identity(Matrix3x2d dest);
+ public abstract void identity(Matrix2f dest);
+ public abstract void swap(Matrix4f m1, Matrix4f m2);
+ public abstract void swap(Matrix4x3f m1, Matrix4x3f m2);
+ public abstract void swap(Matrix3f m1, Matrix3f m2);
+ public abstract void swap(Matrix2f m1, Matrix2f m2);
+ public abstract void swap(Matrix2d m1, Matrix2d m2);
+ public abstract void zero(Matrix4f dest);
+ public abstract void zero(Matrix4x3f dest);
+ public abstract void zero(Matrix3f dest);
+ public abstract void zero(Matrix3x2f dest);
+ public abstract void zero(Matrix3x2d dest);
+ public abstract void zero(Matrix2f dest);
+ public abstract void zero(Matrix2d dest);
+
+ public static class MemUtilNIO extends MemUtil {
+ public void put0(Matrix4f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, m.m03())
+ .put(4, m.m10())
+ .put(5, m.m11())
+ .put(6, m.m12())
+ .put(7, m.m13())
+ .put(8, m.m20())
+ .put(9, m.m21())
+ .put(10, m.m22())
+ .put(11, m.m23())
+ .put(12, m.m30())
+ .put(13, m.m31())
+ .put(14, m.m32())
+ .put(15, m.m33());
+ }
+ public void putN(Matrix4f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m03())
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, m.m13())
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m23())
+ .put(offset+12, m.m30())
+ .put(offset+13, m.m31())
+ .put(offset+14, m.m32())
+ .put(offset+15, m.m33());
+ }
+ public void put(Matrix4f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put0(m, dest);
+ else
+ putN(m, offset, dest);
+ }
+
+ public void put0(Matrix4f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, m.m03())
+ .putFloat(16, m.m10())
+ .putFloat(20, m.m11())
+ .putFloat(24, m.m12())
+ .putFloat(28, m.m13())
+ .putFloat(32, m.m20())
+ .putFloat(36, m.m21())
+ .putFloat(40, m.m22())
+ .putFloat(44, m.m23())
+ .putFloat(48, m.m30())
+ .putFloat(52, m.m31())
+ .putFloat(56, m.m32())
+ .putFloat(60, m.m33());
+ }
+ private void putN(Matrix4f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, m.m03())
+ .putFloat(offset+16, m.m10())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m12())
+ .putFloat(offset+28, m.m13())
+ .putFloat(offset+32, m.m20())
+ .putFloat(offset+36, m.m21())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, m.m23())
+ .putFloat(offset+48, m.m30())
+ .putFloat(offset+52, m.m31())
+ .putFloat(offset+56, m.m32())
+ .putFloat(offset+60, m.m33());
+ }
+ public void put(Matrix4f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put0(m, dest);
+ else
+ putN(m, offset, dest);
+ }
+
+ public void put4x3_0(Matrix4f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, m.m10())
+ .put(4, m.m11())
+ .put(5, m.m12())
+ .put(6, m.m20())
+ .put(7, m.m21())
+ .put(8, m.m22())
+ .put(9, m.m30())
+ .put(10, m.m31())
+ .put(11, m.m32());
+ }
+ public void put4x3_N(Matrix4f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, m.m12())
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, m.m22())
+ .put(offset+9, m.m30())
+ .put(offset+10, m.m31())
+ .put(offset+11, m.m32());
+ }
+ public void put4x3(Matrix4f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put4x3_0(m, dest);
+ else
+ put4x3_N(m, offset, dest);
+ }
+
+ public void put4x3_0(Matrix4f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, m.m10())
+ .putFloat(16, m.m11())
+ .putFloat(20, m.m12())
+ .putFloat(24, m.m20())
+ .putFloat(28, m.m21())
+ .putFloat(32, m.m22())
+ .putFloat(36, m.m30())
+ .putFloat(40, m.m31())
+ .putFloat(44, m.m32());
+ }
+ private void put4x3_N(Matrix4f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, m.m10())
+ .putFloat(offset+16, m.m11())
+ .putFloat(offset+20, m.m12())
+ .putFloat(offset+24, m.m20())
+ .putFloat(offset+28, m.m21())
+ .putFloat(offset+32, m.m22())
+ .putFloat(offset+36, m.m30())
+ .putFloat(offset+40, m.m31())
+ .putFloat(offset+44, m.m32());
+ }
+ public void put4x3(Matrix4f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put4x3_0(m, dest);
+ else
+ put4x3_N(m, offset, dest);
+ }
+
+ public void put3x4_0(Matrix4f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, m.m03())
+ .putFloat(16, m.m10())
+ .putFloat(20, m.m11())
+ .putFloat(24, m.m12())
+ .putFloat(28, m.m13())
+ .putFloat(32, m.m20())
+ .putFloat(36, m.m21())
+ .putFloat(40, m.m22())
+ .putFloat(44, m.m23());
+ }
+ private void put3x4_N(Matrix4f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, m.m03())
+ .putFloat(offset+16, m.m10())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m12())
+ .putFloat(offset+28, m.m13())
+ .putFloat(offset+32, m.m20())
+ .putFloat(offset+36, m.m21())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, m.m23());
+ }
+ public void put3x4(Matrix4f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put3x4_0(m, dest);
+ else
+ put3x4_N(m, offset, dest);
+ }
+
+ public void put3x4_0(Matrix4f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, m.m03())
+ .put(4, m.m10())
+ .put(5, m.m11())
+ .put(6, m.m12())
+ .put(7, m.m13())
+ .put(8, m.m20())
+ .put(9, m.m21())
+ .put(10, m.m22())
+ .put(11, m.m23());
+ }
+ public void put3x4_N(Matrix4f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m03())
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, m.m13())
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m23());
+ }
+ public void put3x4(Matrix4f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put3x4_0(m, dest);
+ else
+ put3x4_N(m, offset, dest);
+ }
+
+ public void put3x4_0(Matrix4x3f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, 0.0f)
+ .putFloat(16, m.m10())
+ .putFloat(20, m.m11())
+ .putFloat(24, m.m12())
+ .putFloat(28, 0.0f)
+ .putFloat(32, m.m20())
+ .putFloat(36, m.m21())
+ .putFloat(40, m.m22())
+ .putFloat(44, 0.0f);
+ }
+ private void put3x4_N(Matrix4x3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, 0.0f)
+ .putFloat(offset+16, m.m10())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m12())
+ .putFloat(offset+28, 0.0f)
+ .putFloat(offset+32, m.m20())
+ .putFloat(offset+36, m.m21())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, 0.0f);
+ }
+ public void put3x4(Matrix4x3f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put3x4_0(m, dest);
+ else
+ put3x4_N(m, offset, dest);
+ }
+
+ public void put3x4_0(Matrix4x3f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, 0.0f)
+ .put(4, m.m10())
+ .put(5, m.m11())
+ .put(6, m.m12())
+ .put(7, 0.0f)
+ .put(8, m.m20())
+ .put(9, m.m21())
+ .put(10, m.m22())
+ .put(11, 0.0f);
+ }
+ public void put3x4_N(Matrix4x3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, 0.0f)
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, 0.0f)
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, 0.0f);
+ }
+ public void put3x4(Matrix4x3f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put3x4_0(m, dest);
+ else
+ put3x4_N(m, offset, dest);
+ }
+
+ public void put0(Matrix4x3f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, m.m10())
+ .put(4, m.m11())
+ .put(5, m.m12())
+ .put(6, m.m20())
+ .put(7, m.m21())
+ .put(8, m.m22())
+ .put(9, m.m30())
+ .put(10, m.m31())
+ .put(11, m.m32());
+ }
+ public void putN(Matrix4x3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, m.m12())
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, m.m22())
+ .put(offset+9, m.m30())
+ .put(offset+10, m.m31())
+ .put(offset+11, m.m32());
+ }
+ public void put(Matrix4x3f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put0(m, dest);
+ else
+ putN(m, offset, dest);
+ }
+
+ public void put0(Matrix4x3f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, m.m10())
+ .putFloat(16, m.m11())
+ .putFloat(20, m.m12())
+ .putFloat(24, m.m20())
+ .putFloat(28, m.m21())
+ .putFloat(32, m.m22())
+ .putFloat(36, m.m30())
+ .putFloat(40, m.m31())
+ .putFloat(44, m.m32());
+ }
+ public void putN(Matrix4x3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, m.m10())
+ .putFloat(offset+16, m.m11())
+ .putFloat(offset+20, m.m12())
+ .putFloat(offset+24, m.m20())
+ .putFloat(offset+28, m.m21())
+ .putFloat(offset+32, m.m22())
+ .putFloat(offset+36, m.m30())
+ .putFloat(offset+40, m.m31())
+ .putFloat(offset+44, m.m32());
+ }
+ public void put(Matrix4x3f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put0(m, dest);
+ else
+ putN(m, offset, dest);
+ }
+
+ public void put4x4(Matrix4x3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, 0.0f)
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, 0.0f)
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, 0.0f)
+ .put(offset+12, m.m30())
+ .put(offset+13, m.m31())
+ .put(offset+14, m.m32())
+ .put(offset+15, 1.0f);
+ }
+
+ public void put4x4(Matrix4x3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, 0.0f)
+ .putFloat(offset+16, m.m10())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m12())
+ .putFloat(offset+28, 0.0f)
+ .putFloat(offset+32, m.m20())
+ .putFloat(offset+36, m.m21())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, 0.0f)
+ .putFloat(offset+48, m.m30())
+ .putFloat(offset+52, m.m31())
+ .putFloat(offset+56, m.m32())
+ .putFloat(offset+60, 1.0f);
+ }
+
+ public void put4x4(Matrix4x3d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, 0.0)
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, 0.0)
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, 0.0)
+ .put(offset+12, m.m30())
+ .put(offset+13, m.m31())
+ .put(offset+14, m.m32())
+ .put(offset+15, 1.0);
+ }
+
+ public void put4x4(Matrix4x3d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, m.m02())
+ .putDouble(offset+24, 0.0)
+ .putDouble(offset+32, m.m10())
+ .putDouble(offset+40, m.m11())
+ .putDouble(offset+48, m.m12())
+ .putDouble(offset+56, 0.0)
+ .putDouble(offset+64, m.m20())
+ .putDouble(offset+72, m.m21())
+ .putDouble(offset+80, m.m22())
+ .putDouble(offset+88, 0.0)
+ .putDouble(offset+96, m.m30())
+ .putDouble(offset+104, m.m31())
+ .putDouble(offset+112, m.m32())
+ .putDouble(offset+120, 1.0);
+ }
+
+ public void put4x4(Matrix3x2f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, 0.0f)
+ .put(offset+3, 0.0f)
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, 0.0f)
+ .put(offset+7, 0.0f)
+ .put(offset+8, 0.0f)
+ .put(offset+9, 0.0f)
+ .put(offset+10, 1.0f)
+ .put(offset+11, 0.0f)
+ .put(offset+12, m.m20())
+ .put(offset+13, m.m21())
+ .put(offset+14, 0.0f)
+ .put(offset+15, 1.0f);
+ }
+
+ public void put4x4(Matrix3x2f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, 0.0f)
+ .putFloat(offset+12, 0.0f)
+ .putFloat(offset+16, m.m10())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, 0.0f)
+ .putFloat(offset+28, 0.0f)
+ .putFloat(offset+32, 0.0f)
+ .putFloat(offset+36, 0.0f)
+ .putFloat(offset+40, 1.0f)
+ .putFloat(offset+44, 0.0f)
+ .putFloat(offset+48, m.m20())
+ .putFloat(offset+52, m.m21())
+ .putFloat(offset+56, 0.0f)
+ .putFloat(offset+60, 1.0f);
+ }
+
+ public void put4x4(Matrix3x2d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, 0.0)
+ .put(offset+3, 0.0)
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, 0.0)
+ .put(offset+7, 0.0)
+ .put(offset+8, 0.0)
+ .put(offset+9, 0.0)
+ .put(offset+10, 1.0)
+ .put(offset+11, 0.0)
+ .put(offset+12, m.m20())
+ .put(offset+13, m.m21())
+ .put(offset+14, 0.0)
+ .put(offset+15, 1.0);
+ }
+
+ public void put4x4(Matrix3x2d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, 0.0)
+ .putDouble(offset+24, 0.0)
+ .putDouble(offset+32, m.m10())
+ .putDouble(offset+40, m.m11())
+ .putDouble(offset+48, 0.0)
+ .putDouble(offset+56, 0.0)
+ .putDouble(offset+64, 0.0)
+ .putDouble(offset+72, 0.0)
+ .putDouble(offset+80, 1.0)
+ .putDouble(offset+88, 0.0)
+ .putDouble(offset+96, m.m20())
+ .putDouble(offset+104, m.m21())
+ .putDouble(offset+112, 0.0)
+ .putDouble(offset+120, 1.0);
+ }
+
+ public void put3x3(Matrix3x2f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, 0.0f)
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, 0.0f)
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, 1.0f);
+ }
+
+ public void put3x3(Matrix3x2f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, 0.0f)
+ .putFloat(offset+12, m.m10())
+ .putFloat(offset+16, m.m11())
+ .putFloat(offset+20, 0.0f)
+ .putFloat(offset+24, m.m20())
+ .putFloat(offset+28, m.m21())
+ .putFloat(offset+32, 1.0f);
+ }
+
+ public void put3x3(Matrix3x2d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, 0.0)
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, 0.0)
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, 1.0);
+ }
+
+ public void put3x3(Matrix3x2d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, 0.0)
+ .putDouble(offset+24, m.m10())
+ .putDouble(offset+32, m.m11())
+ .putDouble(offset+40, 0.0)
+ .putDouble(offset+48, m.m20())
+ .putDouble(offset+56, m.m21())
+ .putDouble(offset+64, 1.0);
+ }
+
+ private void putTransposedN(Matrix4f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m30())
+ .put(offset+4, m.m01())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m21())
+ .put(offset+7, m.m31())
+ .put(offset+8, m.m02())
+ .put(offset+9, m.m12())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m32())
+ .put(offset+12, m.m03())
+ .put(offset+13, m.m13())
+ .put(offset+14, m.m23())
+ .put(offset+15, m.m33());
+ }
+ private void putTransposed0(Matrix4f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m10())
+ .put(2, m.m20())
+ .put(3, m.m30())
+ .put(4, m.m01())
+ .put(5, m.m11())
+ .put(6, m.m21())
+ .put(7, m.m31())
+ .put(8, m.m02())
+ .put(9, m.m12())
+ .put(10, m.m22())
+ .put(11, m.m32())
+ .put(12, m.m03())
+ .put(13, m.m13())
+ .put(14, m.m23())
+ .put(15, m.m33());
+ }
+ public void putTransposed(Matrix4f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ putTransposed0(m, dest);
+ else
+ putTransposedN(m, offset, dest);
+ }
+
+ private void putTransposedN(Matrix4f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m10())
+ .putFloat(offset+8, m.m20())
+ .putFloat(offset+12, m.m30())
+ .putFloat(offset+16, m.m01())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m21())
+ .putFloat(offset+28, m.m31())
+ .putFloat(offset+32, m.m02())
+ .putFloat(offset+36, m.m12())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, m.m32())
+ .putFloat(offset+48, m.m03())
+ .putFloat(offset+52, m.m13())
+ .putFloat(offset+56, m.m23())
+ .putFloat(offset+60, m.m33());
+ }
+ private void putTransposed0(Matrix4f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m10())
+ .putFloat(8, m.m20())
+ .putFloat(12, m.m30())
+ .putFloat(16, m.m01())
+ .putFloat(20, m.m11())
+ .putFloat(24, m.m21())
+ .putFloat(28, m.m31())
+ .putFloat(32, m.m02())
+ .putFloat(36, m.m12())
+ .putFloat(40, m.m22())
+ .putFloat(44, m.m32())
+ .putFloat(48, m.m03())
+ .putFloat(52, m.m13())
+ .putFloat(56, m.m23())
+ .putFloat(60, m.m33());
+ }
+ public void putTransposed(Matrix4f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ putTransposed0(m, dest);
+ else
+ putTransposedN(m, offset, dest);
+ }
+
+ public void put4x3Transposed(Matrix4f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m30())
+ .put(offset+4, m.m01())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m21())
+ .put(offset+7, m.m31())
+ .put(offset+8, m.m02())
+ .put(offset+9, m.m12())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m32());
+ }
+
+ public void put4x3Transposed(Matrix4f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m10())
+ .putFloat(offset+8, m.m20())
+ .putFloat(offset+12, m.m30())
+ .putFloat(offset+16, m.m01())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m21())
+ .putFloat(offset+28, m.m31())
+ .putFloat(offset+32, m.m02())
+ .putFloat(offset+36, m.m12())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, m.m32());
+ }
+
+ public void putTransposed(Matrix4x3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m30())
+ .put(offset+4, m.m01())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m21())
+ .put(offset+7, m.m31())
+ .put(offset+8, m.m02())
+ .put(offset+9, m.m12())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m32());
+ }
+
+ public void putTransposed(Matrix4x3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m10())
+ .putFloat(offset+8, m.m20())
+ .putFloat(offset+12, m.m30())
+ .putFloat(offset+16, m.m01())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m21())
+ .putFloat(offset+28, m.m31())
+ .putFloat(offset+32, m.m02())
+ .putFloat(offset+36, m.m12())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, m.m32());
+ }
+
+ public void putTransposed(Matrix3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m01())
+ .put(offset+4, m.m11())
+ .put(offset+5, m.m21())
+ .put(offset+6, m.m02())
+ .put(offset+7, m.m12())
+ .put(offset+8, m.m22());
+ }
+
+ public void putTransposed(Matrix3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m10())
+ .putFloat(offset+8, m.m20())
+ .putFloat(offset+12, m.m01())
+ .putFloat(offset+16, m.m11())
+ .putFloat(offset+20, m.m21())
+ .putFloat(offset+24, m.m02())
+ .putFloat(offset+28, m.m12())
+ .putFloat(offset+32, m.m22());
+ }
+
+ public void putTransposed(Matrix2f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m01())
+ .put(offset+3, m.m11());
+ }
+
+ public void putTransposed(Matrix2f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m10())
+ .putFloat(offset+8, m.m01())
+ .putFloat(offset+12, m.m11());
+ }
+
+ public void put(Matrix4d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m03())
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, m.m13())
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m23())
+ .put(offset+12, m.m30())
+ .put(offset+13, m.m31())
+ .put(offset+14, m.m32())
+ .put(offset+15, m.m33());
+ }
+
+ public void put(Matrix4d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, m.m02())
+ .putDouble(offset+24, m.m03())
+ .putDouble(offset+32, m.m10())
+ .putDouble(offset+40, m.m11())
+ .putDouble(offset+48, m.m12())
+ .putDouble(offset+56, m.m13())
+ .putDouble(offset+64, m.m20())
+ .putDouble(offset+72, m.m21())
+ .putDouble(offset+80, m.m22())
+ .putDouble(offset+88, m.m23())
+ .putDouble(offset+96, m.m30())
+ .putDouble(offset+104, m.m31())
+ .putDouble(offset+112, m.m32())
+ .putDouble(offset+120, m.m33());
+ }
+
+ public void put(Matrix4x3d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, m.m12())
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, m.m22())
+ .put(offset+9, m.m30())
+ .put(offset+10, m.m31())
+ .put(offset+11, m.m32());
+ }
+
+ public void put(Matrix4x3d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, m.m02())
+ .putDouble(offset+24, m.m10())
+ .putDouble(offset+32, m.m11())
+ .putDouble(offset+40, m.m12())
+ .putDouble(offset+48, m.m20())
+ .putDouble(offset+56, m.m21())
+ .putDouble(offset+64, m.m22())
+ .putDouble(offset+72, m.m30())
+ .putDouble(offset+80, m.m31())
+ .putDouble(offset+88, m.m32());
+ }
+
+ public void putf(Matrix4d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m01())
+ .put(offset+2, (float)m.m02())
+ .put(offset+3, (float)m.m03())
+ .put(offset+4, (float)m.m10())
+ .put(offset+5, (float)m.m11())
+ .put(offset+6, (float)m.m12())
+ .put(offset+7, (float)m.m13())
+ .put(offset+8, (float)m.m20())
+ .put(offset+9, (float)m.m21())
+ .put(offset+10, (float)m.m22())
+ .put(offset+11, (float)m.m23())
+ .put(offset+12, (float)m.m30())
+ .put(offset+13, (float)m.m31())
+ .put(offset+14, (float)m.m32())
+ .put(offset+15, (float)m.m33());
+ }
+
+ public void putf(Matrix4d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m01())
+ .putFloat(offset+8, (float)m.m02())
+ .putFloat(offset+12, (float)m.m03())
+ .putFloat(offset+16, (float)m.m10())
+ .putFloat(offset+20, (float)m.m11())
+ .putFloat(offset+24, (float)m.m12())
+ .putFloat(offset+28, (float)m.m13())
+ .putFloat(offset+32, (float)m.m20())
+ .putFloat(offset+36, (float)m.m21())
+ .putFloat(offset+40, (float)m.m22())
+ .putFloat(offset+44, (float)m.m23())
+ .putFloat(offset+48, (float)m.m30())
+ .putFloat(offset+52, (float)m.m31())
+ .putFloat(offset+56, (float)m.m32())
+ .putFloat(offset+60, (float)m.m33());
+ }
+
+ public void putf(Matrix4x3d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m01())
+ .put(offset+2, (float)m.m02())
+ .put(offset+3, (float)m.m10())
+ .put(offset+4, (float)m.m11())
+ .put(offset+5, (float)m.m12())
+ .put(offset+6, (float)m.m20())
+ .put(offset+7, (float)m.m21())
+ .put(offset+8, (float)m.m22())
+ .put(offset+9, (float)m.m30())
+ .put(offset+10, (float)m.m31())
+ .put(offset+11, (float)m.m32());
+ }
+
+ public void putf(Matrix4x3d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m01())
+ .putFloat(offset+8, (float)m.m02())
+ .putFloat(offset+12, (float)m.m10())
+ .putFloat(offset+16, (float)m.m11())
+ .putFloat(offset+20, (float)m.m12())
+ .putFloat(offset+24, (float)m.m20())
+ .putFloat(offset+28, (float)m.m21())
+ .putFloat(offset+32, (float)m.m22())
+ .putFloat(offset+36, (float)m.m30())
+ .putFloat(offset+40, (float)m.m31())
+ .putFloat(offset+44, (float)m.m32());
+ }
+
+ public void putTransposed(Matrix4d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m30())
+ .put(offset+4, m.m01())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m21())
+ .put(offset+7, m.m31())
+ .put(offset+8, m.m02())
+ .put(offset+9, m.m12())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m32())
+ .put(offset+12, m.m03())
+ .put(offset+13, m.m13())
+ .put(offset+14, m.m23())
+ .put(offset+15, m.m33());
+ }
+
+ public void putTransposed(Matrix4d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m10())
+ .putDouble(offset+16, m.m20())
+ .putDouble(offset+24, m.m30())
+ .putDouble(offset+32, m.m01())
+ .putDouble(offset+40, m.m11())
+ .putDouble(offset+48, m.m21())
+ .putDouble(offset+56, m.m31())
+ .putDouble(offset+64, m.m02())
+ .putDouble(offset+72, m.m12())
+ .putDouble(offset+80, m.m22())
+ .putDouble(offset+88, m.m32())
+ .putDouble(offset+96, m.m03())
+ .putDouble(offset+104, m.m13())
+ .putDouble(offset+112, m.m23())
+ .putDouble(offset+120, m.m33());
+ }
+
+ public void put4x3Transposed(Matrix4d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m30())
+ .put(offset+4, m.m01())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m21())
+ .put(offset+7, m.m31())
+ .put(offset+8, m.m02())
+ .put(offset+9, m.m12())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m32());
+ }
+
+ public void put4x3Transposed(Matrix4d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m10())
+ .putDouble(offset+16, m.m20())
+ .putDouble(offset+24, m.m30())
+ .putDouble(offset+32, m.m01())
+ .putDouble(offset+40, m.m11())
+ .putDouble(offset+48, m.m21())
+ .putDouble(offset+56, m.m31())
+ .putDouble(offset+64, m.m02())
+ .putDouble(offset+72, m.m12())
+ .putDouble(offset+80, m.m22())
+ .putDouble(offset+88, m.m32());
+ }
+
+ public void putTransposed(Matrix4x3d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m20())
+ .put(offset+3, m.m30())
+ .put(offset+4, m.m01())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m21())
+ .put(offset+7, m.m31())
+ .put(offset+8, m.m02())
+ .put(offset+9, m.m12())
+ .put(offset+10, m.m22())
+ .put(offset+11, m.m32());
+ }
+
+ public void putTransposed(Matrix4x3d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m10())
+ .putDouble(offset+16, m.m20())
+ .putDouble(offset+24, m.m30())
+ .putDouble(offset+32, m.m01())
+ .putDouble(offset+40, m.m11())
+ .putDouble(offset+48, m.m21())
+ .putDouble(offset+56, m.m31())
+ .putDouble(offset+64, m.m02())
+ .putDouble(offset+72, m.m12())
+ .putDouble(offset+80, m.m22())
+ .putDouble(offset+88, m.m32());
+ }
+
+ public void putTransposed(Matrix2d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m10())
+ .put(offset+2, m.m01())
+ .put(offset+3, m.m11());
+ }
+
+ public void putTransposed(Matrix2d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m10())
+ .putDouble(offset+16, m.m01())
+ .putDouble(offset+24, m.m11());
+ }
+
+ public void putfTransposed(Matrix4x3d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m10())
+ .put(offset+2, (float)m.m20())
+ .put(offset+3, (float)m.m30())
+ .put(offset+4, (float)m.m01())
+ .put(offset+5, (float)m.m11())
+ .put(offset+6, (float)m.m21())
+ .put(offset+7, (float)m.m31())
+ .put(offset+8, (float)m.m02())
+ .put(offset+9, (float)m.m12())
+ .put(offset+10, (float)m.m22())
+ .put(offset+11, (float)m.m32());
+ }
+
+ public void putfTransposed(Matrix4x3d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m10())
+ .putFloat(offset+8, (float)m.m20())
+ .putFloat(offset+12, (float)m.m30())
+ .putFloat(offset+16, (float)m.m01())
+ .putFloat(offset+20, (float)m.m11())
+ .putFloat(offset+24, (float)m.m21())
+ .putFloat(offset+28, (float)m.m31())
+ .putFloat(offset+32, (float)m.m02())
+ .putFloat(offset+36, (float)m.m12())
+ .putFloat(offset+40, (float)m.m22())
+ .putFloat(offset+44, (float)m.m32());
+ }
+
+ public void putfTransposed(Matrix2d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m10())
+ .put(offset+2, (float)m.m01())
+ .put(offset+3, (float)m.m11());
+ }
+
+ public void putfTransposed(Matrix2d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m10())
+ .putFloat(offset+8, (float)m.m01())
+ .putFloat(offset+12, (float)m.m11());
+ }
+
+ public void putfTransposed(Matrix4d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m10())
+ .put(offset+2, (float)m.m20())
+ .put(offset+3, (float)m.m30())
+ .put(offset+4, (float)m.m01())
+ .put(offset+5, (float)m.m11())
+ .put(offset+6, (float)m.m21())
+ .put(offset+7, (float)m.m31())
+ .put(offset+8, (float)m.m02())
+ .put(offset+9, (float)m.m12())
+ .put(offset+10, (float)m.m22())
+ .put(offset+11, (float)m.m32())
+ .put(offset+12, (float)m.m03())
+ .put(offset+13, (float)m.m13())
+ .put(offset+14, (float)m.m23())
+ .put(offset+15, (float)m.m33());
+ }
+
+ public void putfTransposed(Matrix4d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m10())
+ .putFloat(offset+8, (float)m.m20())
+ .putFloat(offset+12, (float)m.m30())
+ .putFloat(offset+16, (float)m.m01())
+ .putFloat(offset+20, (float)m.m11())
+ .putFloat(offset+24, (float)m.m21())
+ .putFloat(offset+28, (float)m.m31())
+ .putFloat(offset+32, (float)m.m02())
+ .putFloat(offset+36, (float)m.m12())
+ .putFloat(offset+40, (float)m.m22())
+ .putFloat(offset+44, (float)m.m32())
+ .putFloat(offset+48, (float)m.m03())
+ .putFloat(offset+52, (float)m.m13())
+ .putFloat(offset+56, (float)m.m23())
+ .putFloat(offset+60, (float)m.m33());
+ }
+
+ public void put0(Matrix3f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, m.m10())
+ .put(4, m.m11())
+ .put(5, m.m12())
+ .put(6, m.m20())
+ .put(7, m.m21())
+ .put(8, m.m22());
+ }
+ public void putN(Matrix3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, m.m12())
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, m.m22());
+ }
+ public void put(Matrix3f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put0(m, dest);
+ else
+ putN(m, offset, dest);
+ }
+
+ public void put0(Matrix3f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, m.m10())
+ .putFloat(16, m.m11())
+ .putFloat(20, m.m12())
+ .putFloat(24, m.m20())
+ .putFloat(28, m.m21())
+ .putFloat(32, m.m22());
+ }
+ public void putN(Matrix3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, m.m10())
+ .putFloat(offset+16, m.m11())
+ .putFloat(offset+20, m.m12())
+ .putFloat(offset+24, m.m20())
+ .putFloat(offset+28, m.m21())
+ .putFloat(offset+32, m.m22());
+ }
+ public void put(Matrix3f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put0(m, dest);
+ else
+ putN(m, offset, dest);
+ }
+
+ public void put3x4_0(Matrix3f m, ByteBuffer dest) {
+ dest.putFloat(0, m.m00())
+ .putFloat(4, m.m01())
+ .putFloat(8, m.m02())
+ .putFloat(12, 0.0f)
+ .putFloat(16, m.m10())
+ .putFloat(20, m.m11())
+ .putFloat(24, m.m12())
+ .putFloat(28, 0.0f)
+ .putFloat(32, m.m20())
+ .putFloat(36, m.m21())
+ .putFloat(40, m.m22())
+ .putFloat(44, 0.0f);
+ }
+ private void put3x4_N(Matrix3f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m02())
+ .putFloat(offset+12, 0.0f)
+ .putFloat(offset+16, m.m10())
+ .putFloat(offset+20, m.m11())
+ .putFloat(offset+24, m.m12())
+ .putFloat(offset+28, 0.0f)
+ .putFloat(offset+32, m.m20())
+ .putFloat(offset+36, m.m21())
+ .putFloat(offset+40, m.m22())
+ .putFloat(offset+44, 0.0f);
+ }
+ public void put3x4(Matrix3f m, int offset, ByteBuffer dest) {
+ if (offset == 0)
+ put3x4_0(m, dest);
+ else
+ put3x4_N(m, offset, dest);
+ }
+
+ public void put3x4_0(Matrix3f m, FloatBuffer dest) {
+ dest.put(0, m.m00())
+ .put(1, m.m01())
+ .put(2, m.m02())
+ .put(3, 0.0f)
+ .put(4, m.m10())
+ .put(5, m.m11())
+ .put(6, m.m12())
+ .put(7, 0.0f)
+ .put(8, m.m20())
+ .put(9, m.m21())
+ .put(10, m.m22())
+ .put(11, 0.0f);
+ }
+ public void put3x4_N(Matrix3f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, 0.0f)
+ .put(offset+4, m.m10())
+ .put(offset+5, m.m11())
+ .put(offset+6, m.m12())
+ .put(offset+7, 0.0f)
+ .put(offset+8, m.m20())
+ .put(offset+9, m.m21())
+ .put(offset+10, m.m22())
+ .put(offset+11, 0.0f);
+ }
+ public void put3x4(Matrix3f m, int offset, FloatBuffer dest) {
+ if (offset == 0)
+ put3x4_0(m, dest);
+ else
+ put3x4_N(m, offset, dest);
+ }
+
+ public void put(Matrix3d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m02())
+ .put(offset+3, m.m10())
+ .put(offset+4, m.m11())
+ .put(offset+5, m.m12())
+ .put(offset+6, m.m20())
+ .put(offset+7, m.m21())
+ .put(offset+8, m.m22());
+ }
+
+ public void put(Matrix3d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, m.m02())
+ .putDouble(offset+24, m.m10())
+ .putDouble(offset+32, m.m11())
+ .putDouble(offset+40, m.m12())
+ .putDouble(offset+48, m.m20())
+ .putDouble(offset+56, m.m21())
+ .putDouble(offset+64, m.m22());
+ }
+
+ public void put(Matrix3x2f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m10())
+ .put(offset+3, m.m11())
+ .put(offset+4, m.m20())
+ .put(offset+5, m.m21());
+ }
+
+ public void put(Matrix3x2f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m10())
+ .putFloat(offset+12, m.m11())
+ .putFloat(offset+16, m.m20())
+ .putFloat(offset+20, m.m21());
+ }
+
+ public void put(Matrix3x2d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m10())
+ .put(offset+3, m.m11())
+ .put(offset+4, m.m20())
+ .put(offset+5, m.m21());
+ }
+
+ public void put(Matrix3x2d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, m.m10())
+ .putDouble(offset+24, m.m11())
+ .putDouble(offset+32, m.m20())
+ .putDouble(offset+40, m.m21());
+ }
+
+ public void putf(Matrix3d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m01())
+ .put(offset+2, (float)m.m02())
+ .put(offset+3, (float)m.m10())
+ .put(offset+4, (float)m.m11())
+ .put(offset+5, (float)m.m12())
+ .put(offset+6, (float)m.m20())
+ .put(offset+7, (float)m.m21())
+ .put(offset+8, (float)m.m22());
+ }
+
+ public void put(Matrix2f m, int offset, FloatBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m10())
+ .put(offset+3, m.m11());
+ }
+
+ public void put(Matrix2f m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, m.m00())
+ .putFloat(offset+4, m.m01())
+ .putFloat(offset+8, m.m10())
+ .putFloat(offset+12, m.m11());
+ }
+
+ public void put(Matrix2d m, int offset, DoubleBuffer dest) {
+ dest.put(offset, m.m00())
+ .put(offset+1, m.m01())
+ .put(offset+2, m.m10())
+ .put(offset+3, m.m11());
+ }
+
+ public void put(Matrix2d m, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, m.m00())
+ .putDouble(offset+8, m.m01())
+ .putDouble(offset+16, m.m10())
+ .putDouble(offset+24, m.m11());
+ }
+
+ public void putf(Matrix2d m, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)m.m00())
+ .put(offset+1, (float)m.m01())
+ .put(offset+2, (float)m.m10())
+ .put(offset+3, (float)m.m11());
+ }
+
+ public void putf(Matrix2d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m01())
+ .putFloat(offset+8, (float)m.m10())
+ .putFloat(offset+12, (float)m.m11());
+ }
+
+ public void putf(Matrix3d m, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float)m.m00())
+ .putFloat(offset+4, (float)m.m01())
+ .putFloat(offset+8, (float)m.m02())
+ .putFloat(offset+12, (float)m.m10())
+ .putFloat(offset+16, (float)m.m11())
+ .putFloat(offset+20, (float)m.m12())
+ .putFloat(offset+24, (float)m.m20())
+ .putFloat(offset+28, (float)m.m21())
+ .putFloat(offset+32, (float)m.m22());
+ }
+
+ public void put(Vector4d src, int offset, DoubleBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y)
+ .put(offset+2, src.z)
+ .put(offset+3, src.w);
+ }
+
+ public void put(Vector4d src, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)src.x)
+ .put(offset+1, (float)src.y)
+ .put(offset+2, (float)src.z)
+ .put(offset+3, (float)src.w);
+ }
+
+ public void put(Vector4d src, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, src.x)
+ .putDouble(offset+8, src.y)
+ .putDouble(offset+16, src.z)
+ .putDouble(offset+24, src.w);
+ }
+
+ public void putf(Vector4d src, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float) src.x)
+ .putFloat(offset+4, (float) src.y)
+ .putFloat(offset+8, (float) src.z)
+ .putFloat(offset+12, (float) src.w);
+ }
+
+ public void put(Vector4f src, int offset, FloatBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y)
+ .put(offset+2, src.z)
+ .put(offset+3, src.w);
+ }
+
+ public void put(Vector4f src, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, src.x)
+ .putFloat(offset+4, src.y)
+ .putFloat(offset+8, src.z)
+ .putFloat(offset+12, src.w);
+ }
+
+ public void put(Vector4i src, int offset, IntBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y)
+ .put(offset+2, src.z)
+ .put(offset+3, src.w);
+ }
+
+ public void put(Vector4i src, int offset, ByteBuffer dest) {
+ dest.putInt(offset, src.x)
+ .putInt(offset+4, src.y)
+ .putInt(offset+8, src.z)
+ .putInt(offset+12, src.w);
+ }
+
+ public void put(Vector3f src, int offset, FloatBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y)
+ .put(offset+2, src.z);
+ }
+
+ public void put(Vector3f src, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, src.x)
+ .putFloat(offset+4, src.y)
+ .putFloat(offset+8, src.z);
+ }
+
+ public void put(Vector3d src, int offset, DoubleBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y)
+ .put(offset+2, src.z);
+ }
+
+ public void put(Vector3d src, int offset, FloatBuffer dest) {
+ dest.put(offset, (float)src.x)
+ .put(offset+1, (float)src.y)
+ .put(offset+2, (float)src.z);
+ }
+
+ public void put(Vector3d src, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, src.x)
+ .putDouble(offset+8, src.y)
+ .putDouble(offset+16, src.z);
+ }
+
+ public void putf(Vector3d src, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, (float) src.x)
+ .putFloat(offset+4, (float) src.y)
+ .putFloat(offset+8, (float) src.z);
+ }
+
+ public void put(Vector3i src, int offset, IntBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y)
+ .put(offset+2, src.z);
+ }
+
+ public void put(Vector3i src, int offset, ByteBuffer dest) {
+ dest.putInt(offset, src.x)
+ .putInt(offset+4, src.y)
+ .putInt(offset+8, src.z);
+ }
+
+ public void put(Vector2f src, int offset, FloatBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y);
+ }
+
+ public void put(Vector2f src, int offset, ByteBuffer dest) {
+ dest.putFloat(offset, src.x)
+ .putFloat(offset+4, src.y);
+ }
+
+ public void put(Vector2d src, int offset, DoubleBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y);
+ }
+
+ public void put(Vector2d src, int offset, ByteBuffer dest) {
+ dest.putDouble(offset, src.x)
+ .putDouble(offset+8, src.y);
+ }
+
+ public void put(Vector2i src, int offset, IntBuffer dest) {
+ dest.put(offset, src.x)
+ .put(offset+1, src.y);
+ }
+
+ public void put(Vector2i src, int offset, ByteBuffer dest) {
+ dest.putInt(offset, src.x)
+ .putInt(offset+4, src.y);
+ }
+
+ public void get(Matrix4f m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m03(src.get(offset+3))
+ ._m10(src.get(offset+4))
+ ._m11(src.get(offset+5))
+ ._m12(src.get(offset+6))
+ ._m13(src.get(offset+7))
+ ._m20(src.get(offset+8))
+ ._m21(src.get(offset+9))
+ ._m22(src.get(offset+10))
+ ._m23(src.get(offset+11))
+ ._m30(src.get(offset+12))
+ ._m31(src.get(offset+13))
+ ._m32(src.get(offset+14))
+ ._m33(src.get(offset+15));
+ }
+
+ public void get(Matrix4f m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m02(src.getFloat(offset+8))
+ ._m03(src.getFloat(offset+12))
+ ._m10(src.getFloat(offset+16))
+ ._m11(src.getFloat(offset+20))
+ ._m12(src.getFloat(offset+24))
+ ._m13(src.getFloat(offset+28))
+ ._m20(src.getFloat(offset+32))
+ ._m21(src.getFloat(offset+36))
+ ._m22(src.getFloat(offset+40))
+ ._m23(src.getFloat(offset+44))
+ ._m30(src.getFloat(offset+48))
+ ._m31(src.getFloat(offset+52))
+ ._m32(src.getFloat(offset+56))
+ ._m33(src.getFloat(offset+60));
+ }
+
+ public void getTransposed(Matrix4f m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m10(src.get(offset+1))
+ ._m20(src.get(offset+2))
+ ._m30(src.get(offset+3))
+ ._m01(src.get(offset+4))
+ ._m11(src.get(offset+5))
+ ._m21(src.get(offset+6))
+ ._m31(src.get(offset+7))
+ ._m02(src.get(offset+8))
+ ._m12(src.get(offset+9))
+ ._m22(src.get(offset+10))
+ ._m32(src.get(offset+11))
+ ._m03(src.get(offset+12))
+ ._m13(src.get(offset+13))
+ ._m23(src.get(offset+14))
+ ._m33(src.get(offset+15));
+ }
+
+ public void getTransposed(Matrix4f m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m10(src.getFloat(offset+4))
+ ._m20(src.getFloat(offset+8))
+ ._m30(src.getFloat(offset+12))
+ ._m01(src.getFloat(offset+16))
+ ._m11(src.getFloat(offset+20))
+ ._m21(src.getFloat(offset+24))
+ ._m31(src.getFloat(offset+28))
+ ._m02(src.getFloat(offset+32))
+ ._m12(src.getFloat(offset+36))
+ ._m22(src.getFloat(offset+40))
+ ._m32(src.getFloat(offset+44))
+ ._m03(src.getFloat(offset+48))
+ ._m13(src.getFloat(offset+52))
+ ._m23(src.getFloat(offset+56))
+ ._m33(src.getFloat(offset+60));
+ }
+
+ public void get(Matrix4x3f m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m10(src.get(offset+3))
+ ._m11(src.get(offset+4))
+ ._m12(src.get(offset+5))
+ ._m20(src.get(offset+6))
+ ._m21(src.get(offset+7))
+ ._m22(src.get(offset+8))
+ ._m30(src.get(offset+9))
+ ._m31(src.get(offset+10))
+ ._m32(src.get(offset+11));
+ }
+
+ public void get(Matrix4x3f m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m02(src.getFloat(offset+8))
+ ._m10(src.getFloat(offset+12))
+ ._m11(src.getFloat(offset+16))
+ ._m12(src.getFloat(offset+20))
+ ._m20(src.getFloat(offset+24))
+ ._m21(src.getFloat(offset+28))
+ ._m22(src.getFloat(offset+32))
+ ._m30(src.getFloat(offset+36))
+ ._m31(src.getFloat(offset+40))
+ ._m32(src.getFloat(offset+44));
+ }
+
+ public void get(Matrix4d m, int offset, DoubleBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m03(src.get(offset+3))
+ ._m10(src.get(offset+4))
+ ._m11(src.get(offset+5))
+ ._m12(src.get(offset+6))
+ ._m13(src.get(offset+7))
+ ._m20(src.get(offset+8))
+ ._m21(src.get(offset+9))
+ ._m22(src.get(offset+10))
+ ._m23(src.get(offset+11))
+ ._m30(src.get(offset+12))
+ ._m31(src.get(offset+13))
+ ._m32(src.get(offset+14))
+ ._m33(src.get(offset+15));
+ }
+
+ public void get(Matrix4d m, int offset, ByteBuffer src) {
+ m._m00(src.getDouble(offset))
+ ._m01(src.getDouble(offset+8))
+ ._m02(src.getDouble(offset+16))
+ ._m03(src.getDouble(offset+24))
+ ._m10(src.getDouble(offset+32))
+ ._m11(src.getDouble(offset+40))
+ ._m12(src.getDouble(offset+48))
+ ._m13(src.getDouble(offset+56))
+ ._m20(src.getDouble(offset+64))
+ ._m21(src.getDouble(offset+72))
+ ._m22(src.getDouble(offset+80))
+ ._m23(src.getDouble(offset+88))
+ ._m30(src.getDouble(offset+96))
+ ._m31(src.getDouble(offset+104))
+ ._m32(src.getDouble(offset+112))
+ ._m33(src.getDouble(offset+120));
+ }
+
+ public void get(Matrix4x3d m, int offset, DoubleBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m10(src.get(offset+3))
+ ._m11(src.get(offset+4))
+ ._m12(src.get(offset+5))
+ ._m20(src.get(offset+6))
+ ._m21(src.get(offset+7))
+ ._m22(src.get(offset+8))
+ ._m30(src.get(offset+9))
+ ._m31(src.get(offset+10))
+ ._m32(src.get(offset+11));
+ }
+
+ public void get(Matrix4x3d m, int offset, ByteBuffer src) {
+ m._m00(src.getDouble(offset))
+ ._m01(src.getDouble(offset+8))
+ ._m02(src.getDouble(offset+16))
+ ._m10(src.getDouble(offset+24))
+ ._m11(src.getDouble(offset+32))
+ ._m12(src.getDouble(offset+40))
+ ._m20(src.getDouble(offset+48))
+ ._m21(src.getDouble(offset+56))
+ ._m22(src.getDouble(offset+64))
+ ._m30(src.getDouble(offset+72))
+ ._m31(src.getDouble(offset+80))
+ ._m32(src.getDouble(offset+88));
+ }
+
+ public void getf(Matrix4d m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m03(src.get(offset+3))
+ ._m10(src.get(offset+4))
+ ._m11(src.get(offset+5))
+ ._m12(src.get(offset+6))
+ ._m13(src.get(offset+7))
+ ._m20(src.get(offset+8))
+ ._m21(src.get(offset+9))
+ ._m22(src.get(offset+10))
+ ._m23(src.get(offset+11))
+ ._m30(src.get(offset+12))
+ ._m31(src.get(offset+13))
+ ._m32(src.get(offset+14))
+ ._m33(src.get(offset+15));
+ }
+
+ public void getf(Matrix4d m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m02(src.getFloat(offset+8))
+ ._m03(src.getFloat(offset+12))
+ ._m10(src.getFloat(offset+16))
+ ._m11(src.getFloat(offset+20))
+ ._m12(src.getFloat(offset+24))
+ ._m13(src.getFloat(offset+28))
+ ._m20(src.getFloat(offset+32))
+ ._m21(src.getFloat(offset+36))
+ ._m22(src.getFloat(offset+40))
+ ._m23(src.getFloat(offset+44))
+ ._m30(src.getFloat(offset+48))
+ ._m31(src.getFloat(offset+52))
+ ._m32(src.getFloat(offset+56))
+ ._m33(src.getFloat(offset+60));
+ }
+
+ public void getf(Matrix4x3d m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m10(src.get(offset+3))
+ ._m11(src.get(offset+4))
+ ._m12(src.get(offset+5))
+ ._m20(src.get(offset+6))
+ ._m21(src.get(offset+7))
+ ._m22(src.get(offset+8))
+ ._m30(src.get(offset+9))
+ ._m31(src.get(offset+10))
+ ._m32(src.get(offset+11));
+ }
+
+ public void getf(Matrix4x3d m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m02(src.getFloat(offset+8))
+ ._m10(src.getFloat(offset+12))
+ ._m11(src.getFloat(offset+16))
+ ._m12(src.getFloat(offset+20))
+ ._m20(src.getFloat(offset+24))
+ ._m21(src.getFloat(offset+28))
+ ._m22(src.getFloat(offset+32))
+ ._m30(src.getFloat(offset+36))
+ ._m31(src.getFloat(offset+40))
+ ._m32(src.getFloat(offset+44));
+ }
+
+ public void get(Matrix3f m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m10(src.get(offset+3))
+ ._m11(src.get(offset+4))
+ ._m12(src.get(offset+5))
+ ._m20(src.get(offset+6))
+ ._m21(src.get(offset+7))
+ ._m22(src.get(offset+8));
+ }
+
+ public void get(Matrix3f m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m02(src.getFloat(offset+8))
+ ._m10(src.getFloat(offset+12))
+ ._m11(src.getFloat(offset+16))
+ ._m12(src.getFloat(offset+20))
+ ._m20(src.getFloat(offset+24))
+ ._m21(src.getFloat(offset+28))
+ ._m22(src.getFloat(offset+32));
+ }
+
+ public void get(Matrix3d m, int offset, DoubleBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m10(src.get(offset+3))
+ ._m11(src.get(offset+4))
+ ._m12(src.get(offset+5))
+ ._m20(src.get(offset+6))
+ ._m21(src.get(offset+7))
+ ._m22(src.get(offset+8));
+ }
+
+ public void get(Matrix3d m, int offset, ByteBuffer src) {
+ m._m00(src.getDouble(offset))
+ ._m01(src.getDouble(offset+8))
+ ._m02(src.getDouble(offset+16))
+ ._m10(src.getDouble(offset+24))
+ ._m11(src.getDouble(offset+32))
+ ._m12(src.getDouble(offset+40))
+ ._m20(src.getDouble(offset+48))
+ ._m21(src.getDouble(offset+56))
+ ._m22(src.getDouble(offset+64));
+ }
+
+ public void get(Matrix3x2f m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m10(src.get(offset+2))
+ ._m11(src.get(offset+3))
+ ._m20(src.get(offset+4))
+ ._m21(src.get(offset+5));
+ }
+
+ public void get(Matrix3x2f m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m10(src.getFloat(offset+8))
+ ._m11(src.getFloat(offset+12))
+ ._m20(src.getFloat(offset+16))
+ ._m21(src.getFloat(offset+20));
+ }
+
+ public void get(Matrix3x2d m, int offset, DoubleBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m10(src.get(offset+2))
+ ._m11(src.get(offset+3))
+ ._m20(src.get(offset+4))
+ ._m21(src.get(offset+5));
+ }
+
+ public void get(Matrix3x2d m, int offset, ByteBuffer src) {
+ m._m00(src.getDouble(offset))
+ ._m01(src.getDouble(offset+8))
+ ._m10(src.getDouble(offset+16))
+ ._m11(src.getDouble(offset+24))
+ ._m20(src.getDouble(offset+32))
+ ._m21(src.getDouble(offset+40));
+ }
+
+ public void getf(Matrix3d m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m02(src.get(offset+2))
+ ._m10(src.get(offset+3))
+ ._m11(src.get(offset+4))
+ ._m12(src.get(offset+5))
+ ._m20(src.get(offset+6))
+ ._m21(src.get(offset+7))
+ ._m22(src.get(offset+8));
+ }
+
+ public void getf(Matrix3d m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m02(src.getFloat(offset+8))
+ ._m10(src.getFloat(offset+12))
+ ._m11(src.getFloat(offset+16))
+ ._m12(src.getFloat(offset+20))
+ ._m20(src.getFloat(offset+24))
+ ._m21(src.getFloat(offset+28))
+ ._m22(src.getFloat(offset+32));
+ }
+
+ public void get(Matrix2f m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m10(src.get(offset+2))
+ ._m11(src.get(offset+3));
+ }
+
+ public void get(Matrix2f m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m10(src.getFloat(offset+8))
+ ._m11(src.getFloat(offset+12));
+ }
+
+ public void get(Matrix2d m, int offset, DoubleBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m10(src.get(offset+2))
+ ._m11(src.get(offset+3));
+ }
+
+ public void get(Matrix2d m, int offset, ByteBuffer src) {
+ m._m00(src.getDouble(offset))
+ ._m01(src.getDouble(offset+8))
+ ._m10(src.getDouble(offset+16))
+ ._m11(src.getDouble(offset+24));
+ }
+
+ public void getf(Matrix2d m, int offset, FloatBuffer src) {
+ m._m00(src.get(offset))
+ ._m01(src.get(offset+1))
+ ._m10(src.get(offset+2))
+ ._m11(src.get(offset+3));
+ }
+
+ public void getf(Matrix2d m, int offset, ByteBuffer src) {
+ m._m00(src.getFloat(offset))
+ ._m01(src.getFloat(offset+4))
+ ._m10(src.getFloat(offset+8))
+ ._m11(src.getFloat(offset+12));
+ }
+
+ public void get(Vector4d dst, int offset, DoubleBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ dst.z = src.get(offset+2);
+ dst.w = src.get(offset+3);
+ }
+
+ public void get(Vector4d dst, int offset, ByteBuffer src) {
+ dst.x = src.getDouble(offset);
+ dst.y = src.getDouble(offset+8);
+ dst.z = src.getDouble(offset+16);
+ dst.w = src.getDouble(offset+24);
+ }
+
+ public void get(Vector4f dst, int offset, FloatBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ dst.z = src.get(offset+2);
+ dst.w = src.get(offset+3);
+ }
+
+ public void get(Vector4f dst, int offset, ByteBuffer src) {
+ dst.x = src.getFloat(offset);
+ dst.y = src.getFloat(offset+4);
+ dst.z = src.getFloat(offset+8);
+ dst.w = src.getFloat(offset+12);
+ }
+
+ public void get(Vector4i dst, int offset, IntBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ dst.z = src.get(offset+2);
+ dst.w = src.get(offset+3);
+ }
+
+ public void get(Vector4i dst, int offset, ByteBuffer src) {
+ dst.x = src.getInt(offset);
+ dst.y = src.getInt(offset+4);
+ dst.z = src.getInt(offset+8);
+ dst.w = src.getInt(offset+12);
+ }
+
+ public void get(Vector3f dst, int offset, FloatBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ dst.z = src.get(offset+2);
+ }
+
+ public void get(Vector3f dst, int offset, ByteBuffer src) {
+ dst.x = src.getFloat(offset);
+ dst.y = src.getFloat(offset+4);
+ dst.z = src.getFloat(offset+8);
+ }
+
+ public void get(Vector3d dst, int offset, DoubleBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ dst.z = src.get(offset+2);
+ }
+
+ public void get(Vector3d dst, int offset, ByteBuffer src) {
+ dst.x = src.getDouble(offset);
+ dst.y = src.getDouble(offset+8);
+ dst.z = src.getDouble(offset+16);
+ }
+
+ public void get(Vector3i dst, int offset, IntBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ dst.z = src.get(offset+2);
+ }
+
+ public void get(Vector3i dst, int offset, ByteBuffer src) {
+ dst.x = src.getInt(offset);
+ dst.y = src.getInt(offset+4);
+ dst.z = src.getInt(offset+8);
+ }
+
+ public void get(Vector2f dst, int offset, FloatBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ }
+
+ public void get(Vector2f dst, int offset, ByteBuffer src) {
+ dst.x = src.getFloat(offset);
+ dst.y = src.getFloat(offset+4);
+ }
+
+ public void get(Vector2d dst, int offset, DoubleBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ }
+
+ public void get(Vector2d dst, int offset, ByteBuffer src) {
+ dst.x = src.getDouble(offset);
+ dst.y = src.getDouble(offset+8);
+ }
+
+ public void get(Vector2i dst, int offset, IntBuffer src) {
+ dst.x = src.get(offset);
+ dst.y = src.get(offset+1);
+ }
+
+ public void get(Vector2i dst, int offset, ByteBuffer src) {
+ dst.x = src.getInt(offset);
+ dst.y = src.getInt(offset+4);
+ }
+
+ public float get(Matrix4f m, int column, int row) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00;
+ case 1:
+ return m.m01;
+ case 2:
+ return m.m02;
+ case 3:
+ return m.m03;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10;
+ case 1:
+ return m.m11;
+ case 2:
+ return m.m12;
+ case 3:
+ return m.m13;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20;
+ case 1:
+ return m.m21;
+ case 2:
+ return m.m22;
+ case 3:
+ return m.m23;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (row) {
+ case 0:
+ return m.m30;
+ case 1:
+ return m.m31;
+ case 2:
+ return m.m32;
+ case 3:
+ return m.m33;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public Matrix4f set(Matrix4f m, int column, int row, float value) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00(value);
+ case 1:
+ return m.m01(value);
+ case 2:
+ return m.m02(value);
+ case 3:
+ return m.m03(value);
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10(value);
+ case 1:
+ return m.m11(value);
+ case 2:
+ return m.m12(value);
+ case 3:
+ return m.m13(value);
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20(value);
+ case 1:
+ return m.m21(value);
+ case 2:
+ return m.m22(value);
+ case 3:
+ return m.m23(value);
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (row) {
+ case 0:
+ return m.m30(value);
+ case 1:
+ return m.m31(value);
+ case 2:
+ return m.m32(value);
+ case 3:
+ return m.m33(value);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public double get(Matrix4d m, int column, int row) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00;
+ case 1:
+ return m.m01;
+ case 2:
+ return m.m02;
+ case 3:
+ return m.m03;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10;
+ case 1:
+ return m.m11;
+ case 2:
+ return m.m12;
+ case 3:
+ return m.m13;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20;
+ case 1:
+ return m.m21;
+ case 2:
+ return m.m22;
+ case 3:
+ return m.m23;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (row) {
+ case 0:
+ return m.m30;
+ case 1:
+ return m.m31;
+ case 2:
+ return m.m32;
+ case 3:
+ return m.m33;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public Matrix4d set(Matrix4d m, int column, int row, double value) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00(value);
+ case 1:
+ return m.m01(value);
+ case 2:
+ return m.m02(value);
+ case 3:
+ return m.m03(value);
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10(value);
+ case 1:
+ return m.m11(value);
+ case 2:
+ return m.m12(value);
+ case 3:
+ return m.m13(value);
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20(value);
+ case 1:
+ return m.m21(value);
+ case 2:
+ return m.m22(value);
+ case 3:
+ return m.m23(value);
+ default:
+ break;
+ }
+ break;
+ case 3:
+ switch (row) {
+ case 0:
+ return m.m30(value);
+ case 1:
+ return m.m31(value);
+ case 2:
+ return m.m32(value);
+ case 3:
+ return m.m33(value);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public float get(Matrix3f m, int column, int row) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00;
+ case 1:
+ return m.m01;
+ case 2:
+ return m.m02;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10;
+ case 1:
+ return m.m11;
+ case 2:
+ return m.m12;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20;
+ case 1:
+ return m.m21;
+ case 2:
+ return m.m22;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public Matrix3f set(Matrix3f m, int column, int row, float value) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00(value);
+ case 1:
+ return m.m01(value);
+ case 2:
+ return m.m02(value);
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10(value);
+ case 1:
+ return m.m11(value);
+ case 2:
+ return m.m12(value);
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20(value);
+ case 1:
+ return m.m21(value);
+ case 2:
+ return m.m22(value);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public double get(Matrix3d m, int column, int row) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00;
+ case 1:
+ return m.m01;
+ case 2:
+ return m.m02;
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10;
+ case 1:
+ return m.m11;
+ case 2:
+ return m.m12;
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20;
+ case 1:
+ return m.m21;
+ case 2:
+ return m.m22;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public Matrix3d set(Matrix3d m, int column, int row, double value) {
+ switch (column) {
+ case 0:
+ switch (row) {
+ case 0:
+ return m.m00(value);
+ case 1:
+ return m.m01(value);
+ case 2:
+ return m.m02(value);
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch (row) {
+ case 0:
+ return m.m10(value);
+ case 1:
+ return m.m11(value);
+ case 2:
+ return m.m12(value);
+ default:
+ break;
+ }
+ break;
+ case 2:
+ switch (row) {
+ case 0:
+ return m.m20(value);
+ case 1:
+ return m.m21(value);
+ case 2:
+ return m.m22(value);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ public Vector4f getColumn(Matrix4f m, int column, Vector4f dest) {
+ switch (column) {
+ case 0:
+ return dest.set(m.m00, m.m01, m.m02, m.m03);
+ case 1:
+ return dest.set(m.m10, m.m11, m.m12, m.m13);
+ case 2:
+ return dest.set(m.m20, m.m21, m.m22, m.m23);
+ case 3:
+ return dest.set(m.m30, m.m31, m.m32, m.m33);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public Matrix4f setColumn(Vector4f v, int column, Matrix4f dest) {
+ switch (column) {
+ case 0:
+ return dest._m00(v.x)._m01(v.y)._m02(v.z)._m03(v.w);
+ case 1:
+ return dest._m10(v.x)._m11(v.y)._m12(v.z)._m13(v.w);
+ case 2:
+ return dest._m20(v.x)._m21(v.y)._m22(v.z)._m23(v.w);
+ case 3:
+ return dest._m30(v.x)._m31(v.y)._m32(v.z)._m33(v.w);
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public Matrix4f setColumn(Vector4fc v, int column, Matrix4f dest) {
+ switch (column) {
+ case 0:
+ return dest._m00(v.x())._m01(v.y())._m02(v.z())._m03(v.w());
+ case 1:
+ return dest._m10(v.x())._m11(v.y())._m12(v.z())._m13(v.w());
+ case 2:
+ return dest._m20(v.x())._m21(v.y())._m22(v.z())._m23(v.w());
+ case 3:
+ return dest._m30(v.x())._m31(v.y())._m32(v.z())._m33(v.w());
+ default:
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ public void copy(Matrix4f src, Matrix4f dest) {
+ dest._m00(src.m00()).
+ _m01(src.m01()).
+ _m02(src.m02()).
+ _m03(src.m03()).
+ _m10(src.m10()).
+ _m11(src.m11()).
+ _m12(src.m12()).
+ _m13(src.m13()).
+ _m20(src.m20()).
+ _m21(src.m21()).
+ _m22(src.m22()).
+ _m23(src.m23()).
+ _m30(src.m30()).
+ _m31(src.m31()).
+ _m32(src.m32()).
+ _m33(src.m33());
+ }
+
+ public void copy(Matrix3f src, Matrix4f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m03(0.0f)
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m13(0.0f)
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f);
+ }
+
+ public void copy(Matrix4f src, Matrix3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22());
+ }
+
+ public void copy(Matrix3f src, Matrix4x3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f);
+ }
+
+ public void copy(Matrix3x2f src, Matrix3x2f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m20(src.m20())
+ ._m21(src.m21());
+ }
+
+ public void copy(Matrix3x2d src, Matrix3x2d dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m20(src.m20())
+ ._m21(src.m21());
+ }
+
+ public void copy(Matrix2f src, Matrix2f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11());
+ }
+
+ public void copy(Matrix2d src, Matrix2d dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11());
+ }
+
+ public void copy(Matrix2f src, Matrix3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(0.0f)
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(1.0f);
+ }
+
+ public void copy(Matrix3f src, Matrix2f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11());
+ }
+
+ public void copy(Matrix2f src, Matrix3x2f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m20(0.0f)
+ ._m21(0.0f);
+ }
+
+ public void copy(Matrix3x2f src, Matrix2f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11());
+ }
+
+ public void copy(Matrix2d src, Matrix3d dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(0.0)
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(0.0)
+ ._m20(0.0)
+ ._m21(0.0)
+ ._m22(1.0);
+ }
+
+ public void copy(Matrix3d src, Matrix2d dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11());
+ }
+
+ public void copy(Matrix2d src, Matrix3x2d dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m20(0.0)
+ ._m21(0.0);
+ }
+
+ public void copy(Matrix3x2d src, Matrix2d dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m10(src.m10())
+ ._m11(src.m11());
+ }
+
+ public void copy3x3(Matrix4f src, Matrix4f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22());
+ }
+
+ public void copy3x3(Matrix4x3f src, Matrix4x3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22());
+ }
+
+ public void copy3x3(Matrix3f src, Matrix4x3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22());
+ }
+
+ public void copy3x3(Matrix3f src, Matrix4f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22());
+ }
+
+ public void copy4x3(Matrix4x3f src, Matrix4f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m30(src.m30())
+ ._m31(src.m31())
+ ._m32(src.m32());
+ }
+
+ public void copy4x3(Matrix4f src, Matrix4f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m30(src.m30())
+ ._m31(src.m31())
+ ._m32(src.m32());
+ }
+
+ public void copy(Matrix4f src, Matrix4x3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m30(src.m30())
+ ._m31(src.m31())
+ ._m32(src.m32());
+ }
+
+ public void copy(Matrix4x3f src, Matrix4f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m03(0.0f)
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m13(0.0f)
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m23(0.0f)
+ ._m30(src.m30())
+ ._m31(src.m31())
+ ._m32(src.m32())
+ ._m33(1.0f);
+ }
+
+ public void copy(Matrix4x3f src, Matrix4x3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22())
+ ._m30(src.m30())
+ ._m31(src.m31())
+ ._m32(src.m32());
+ }
+
+ public void copy(Matrix3f src, Matrix3f dest) {
+ dest._m00(src.m00())
+ ._m01(src.m01())
+ ._m02(src.m02())
+ ._m10(src.m10())
+ ._m11(src.m11())
+ ._m12(src.m12())
+ ._m20(src.m20())
+ ._m21(src.m21())
+ ._m22(src.m22());
+ }
+
+ public void copy(float[] arr, int off, Matrix4f dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m02(arr[off+2])
+ ._m03(arr[off+3])
+ ._m10(arr[off+4])
+ ._m11(arr[off+5])
+ ._m12(arr[off+6])
+ ._m13(arr[off+7])
+ ._m20(arr[off+8])
+ ._m21(arr[off+9])
+ ._m22(arr[off+10])
+ ._m23(arr[off+11])
+ ._m30(arr[off+12])
+ ._m31(arr[off+13])
+ ._m32(arr[off+14])
+ ._m33(arr[off+15]);
+ }
+
+ public void copyTransposed(float[] arr, int off, Matrix4f dest) {
+ dest._m00(arr[off+0])
+ ._m10(arr[off+1])
+ ._m20(arr[off+2])
+ ._m30(arr[off+3])
+ ._m01(arr[off+4])
+ ._m11(arr[off+5])
+ ._m21(arr[off+6])
+ ._m31(arr[off+7])
+ ._m02(arr[off+8])
+ ._m12(arr[off+9])
+ ._m22(arr[off+10])
+ ._m32(arr[off+11])
+ ._m03(arr[off+12])
+ ._m13(arr[off+13])
+ ._m23(arr[off+14])
+ ._m33(arr[off+15]);
+ }
+
+ public void copy(float[] arr, int off, Matrix3f dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m02(arr[off+2])
+ ._m10(arr[off+3])
+ ._m11(arr[off+4])
+ ._m12(arr[off+5])
+ ._m20(arr[off+6])
+ ._m21(arr[off+7])
+ ._m22(arr[off+8]);
+ }
+
+ public void copy(float[] arr, int off, Matrix4x3f dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m02(arr[off+2])
+ ._m10(arr[off+3])
+ ._m11(arr[off+4])
+ ._m12(arr[off+5])
+ ._m20(arr[off+6])
+ ._m21(arr[off+7])
+ ._m22(arr[off+8])
+ ._m30(arr[off+9])
+ ._m31(arr[off+10])
+ ._m32(arr[off+11]);
+ }
+
+ public void copy(float[] arr, int off, Matrix3x2f dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m10(arr[off+2])
+ ._m11(arr[off+3])
+ ._m20(arr[off+4])
+ ._m21(arr[off+5]);
+ }
+
+ public void copy(double[] arr, int off, Matrix3x2d dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m10(arr[off+2])
+ ._m11(arr[off+3])
+ ._m20(arr[off+4])
+ ._m21(arr[off+5]);
+ }
+
+ public void copy(float[] arr, int off, Matrix2f dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m10(arr[off+2])
+ ._m11(arr[off+3]);
+ }
+
+ public void copy(double[] arr, int off, Matrix2d dest) {
+ dest._m00(arr[off+0])
+ ._m01(arr[off+1])
+ ._m10(arr[off+2])
+ ._m11(arr[off+3]);
+ }
+
+ public void copy(Matrix4f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m02();
+ dest[off+3] = src.m03();
+ dest[off+4] = src.m10();
+ dest[off+5] = src.m11();
+ dest[off+6] = src.m12();
+ dest[off+7] = src.m13();
+ dest[off+8] = src.m20();
+ dest[off+9] = src.m21();
+ dest[off+10] = src.m22();
+ dest[off+11] = src.m23();
+ dest[off+12] = src.m30();
+ dest[off+13] = src.m31();
+ dest[off+14] = src.m32();
+ dest[off+15] = src.m33();
+ }
+
+ public void copy(Matrix3f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m02();
+ dest[off+3] = src.m10();
+ dest[off+4] = src.m11();
+ dest[off+5] = src.m12();
+ dest[off+6] = src.m20();
+ dest[off+7] = src.m21();
+ dest[off+8] = src.m22();
+ }
+
+ public void copy(Matrix4x3f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m02();
+ dest[off+3] = src.m10();
+ dest[off+4] = src.m11();
+ dest[off+5] = src.m12();
+ dest[off+6] = src.m20();
+ dest[off+7] = src.m21();
+ dest[off+8] = src.m22();
+ dest[off+9] = src.m30();
+ dest[off+10] = src.m31();
+ dest[off+11] = src.m32();
+ }
+
+ public void copy(Matrix3x2f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m10();
+ dest[off+3] = src.m11();
+ dest[off+4] = src.m20();
+ dest[off+5] = src.m21();
+ }
+
+ public void copy(Matrix3x2d src, double[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m10();
+ dest[off+3] = src.m11();
+ dest[off+4] = src.m20();
+ dest[off+5] = src.m21();
+ }
+
+ public void copy(Matrix2f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m10();
+ dest[off+3] = src.m11();
+ }
+
+ public void copy(Matrix2d src, double[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m10();
+ dest[off+3] = src.m11();
+ }
+
+ public void copy4x4(Matrix4x3f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m02();
+ dest[off+3] = 0.0f;
+ dest[off+4] = src.m10();
+ dest[off+5] = src.m11();
+ dest[off+6] = src.m12();
+ dest[off+7] = 0.0f;
+ dest[off+8] = src.m20();
+ dest[off+9] = src.m21();
+ dest[off+10] = src.m22();
+ dest[off+11] = 0.0f;
+ dest[off+12] = src.m30();
+ dest[off+13] = src.m31();
+ dest[off+14] = src.m32();
+ dest[off+15] = 1.0f;
+ }
+
+ public void copy4x4(Matrix4x3d src, float[] dest, int off) {
+ dest[off+0] = (float) src.m00();
+ dest[off+1] = (float) src.m01();
+ dest[off+2] = (float) src.m02();
+ dest[off+3] = 0.0f;
+ dest[off+4] = (float) src.m10();
+ dest[off+5] = (float) src.m11();
+ dest[off+6] = (float) src.m12();
+ dest[off+7] = 0.0f;
+ dest[off+8] = (float) src.m20();
+ dest[off+9] = (float) src.m21();
+ dest[off+10] = (float) src.m22();
+ dest[off+11] = 0.0f;
+ dest[off+12] = (float) src.m30();
+ dest[off+13] = (float) src.m31();
+ dest[off+14] = (float) src.m32();
+ dest[off+15] = 1.0f;
+ }
+
+ public void copy4x4(Matrix4x3d src, double[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = src.m02();
+ dest[off+3] = 0.0;
+ dest[off+4] = src.m10();
+ dest[off+5] = src.m11();
+ dest[off+6] = src.m12();
+ dest[off+7] = 0.0;
+ dest[off+8] = src.m20();
+ dest[off+9] = src.m21();
+ dest[off+10] = src.m22();
+ dest[off+11] = 0.0;
+ dest[off+12] = src.m30();
+ dest[off+13] = src.m31();
+ dest[off+14] = src.m32();
+ dest[off+15] = 1.0;
+ }
+
+ public void copy3x3(Matrix3x2f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = 0.0f;
+ dest[off+3] = src.m10();
+ dest[off+4] = src.m11();
+ dest[off+5] = 0.0f;
+ dest[off+6] = src.m20();
+ dest[off+7] = src.m21();
+ dest[off+8] = 1.0f;
+ }
+
+ public void copy3x3(Matrix3x2d src, double[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = 0.0;
+ dest[off+3] = src.m10();
+ dest[off+4] = src.m11();
+ dest[off+5] = 0.0;
+ dest[off+6] = src.m20();
+ dest[off+7] = src.m21();
+ dest[off+8] = 1.0;
+ }
+
+ public void copy4x4(Matrix3x2f src, float[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = 0.0f;
+ dest[off+3] = 0.0f;
+ dest[off+4] = src.m10();
+ dest[off+5] = src.m11();
+ dest[off+6] = 0.0f;
+ dest[off+7] = 0.0f;
+ dest[off+8] = 0.0f;
+ dest[off+9] = 0.0f;
+ dest[off+10] = 1.0f;
+ dest[off+11] = 0.0f;
+ dest[off+12] = src.m20();
+ dest[off+13] = src.m21();
+ dest[off+14] = 0.0f;
+ dest[off+15] = 1.0f;
+ }
+
+ public void copy4x4(Matrix3x2d src, double[] dest, int off) {
+ dest[off+0] = src.m00();
+ dest[off+1] = src.m01();
+ dest[off+2] = 0.0;
+ dest[off+3] = 0.0;
+ dest[off+4] = src.m10();
+ dest[off+5] = src.m11();
+ dest[off+6] = 0.0;
+ dest[off+7] = 0.0;
+ dest[off+8] = 0.0;
+ dest[off+9] = 0.0;
+ dest[off+10] = 1.0;
+ dest[off+11] = 0.0;
+ dest[off+12] = src.m20();
+ dest[off+13] = src.m21();
+ dest[off+14] = 0.0;
+ dest[off+15] = 1.0;
+ }
+
+ public void identity(Matrix4f dest) {
+ dest._m00(1.0f)
+ ._m01(0.0f)
+ ._m02(0.0f)
+ ._m03(0.0f)
+ ._m10(0.0f)
+ ._m11(1.0f)
+ ._m12(0.0f)
+ ._m13(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(1.0f)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(1.0f);
+ }
+
+ public void identity(Matrix4x3f dest) {
+ dest._m00(1.0f)
+ ._m01(0.0f)
+ ._m02(0.0f)
+ ._m10(0.0f)
+ ._m11(1.0f)
+ ._m12(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(1.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f);
+ }
+
+ public void identity(Matrix3f dest) {
+ dest._m00(1.0f)
+ ._m01(0.0f)
+ ._m02(0.0f)
+ ._m10(0.0f)
+ ._m11(1.0f)
+ ._m12(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(1.0f);
+ }
+
+ public void identity(Matrix3x2f dest) {
+ dest._m00(1.0f)
+ ._m01(0.0f)
+ ._m10(0.0f)
+ ._m11(1.0f)
+ ._m20(0.0f)
+ ._m21(0.0f);
+ }
+
+ public void identity(Matrix3x2d dest) {
+ dest._m00(1.0)
+ ._m01(0.0)
+ ._m10(0.0)
+ ._m11(1.0)
+ ._m20(0.0)
+ ._m21(0.0);
+ }
+
+ public void identity(Matrix2f dest) {
+ dest._m00(1.0f)
+ ._m01(0.0f)
+ ._m10(0.0f)
+ ._m11(1.0f);
+ }
+
+ public void swap(Matrix4f m1, Matrix4f m2) {
+ float tmp;
+ tmp = m1.m00(); m1._m00(m2.m00()); m2._m00(tmp);
+ tmp = m1.m01(); m1._m01(m2.m01()); m2._m01(tmp);
+ tmp = m1.m02(); m1._m02(m2.m02()); m2._m02(tmp);
+ tmp = m1.m03(); m1._m03(m2.m03()); m2._m03(tmp);
+ tmp = m1.m10(); m1._m10(m2.m10()); m2._m10(tmp);
+ tmp = m1.m11(); m1._m11(m2.m11()); m2._m11(tmp);
+ tmp = m1.m12(); m1._m12(m2.m12()); m2._m12(tmp);
+ tmp = m1.m13(); m1._m13(m2.m13()); m2._m13(tmp);
+ tmp = m1.m20(); m1._m20(m2.m20()); m2._m20(tmp);
+ tmp = m1.m21(); m1._m21(m2.m21()); m2._m21(tmp);
+ tmp = m1.m22(); m1._m22(m2.m22()); m2._m22(tmp);
+ tmp = m1.m23(); m1._m23(m2.m23()); m2._m23(tmp);
+ tmp = m1.m30(); m1._m30(m2.m30()); m2._m30(tmp);
+ tmp = m1.m31(); m1._m31(m2.m31()); m2._m31(tmp);
+ tmp = m1.m32(); m1._m32(m2.m32()); m2._m32(tmp);
+ tmp = m1.m33(); m1._m33(m2.m33()); m2._m33(tmp);
+ }
+
+ public void swap(Matrix4x3f m1, Matrix4x3f m2) {
+ float tmp;
+ tmp = m1.m00(); m1._m00(m2.m00()); m2._m00(tmp);
+ tmp = m1.m01(); m1._m01(m2.m01()); m2._m01(tmp);
+ tmp = m1.m02(); m1._m02(m2.m02()); m2._m02(tmp);
+ tmp = m1.m10(); m1._m10(m2.m10()); m2._m10(tmp);
+ tmp = m1.m11(); m1._m11(m2.m11()); m2._m11(tmp);
+ tmp = m1.m12(); m1._m12(m2.m12()); m2._m12(tmp);
+ tmp = m1.m20(); m1._m20(m2.m20()); m2._m20(tmp);
+ tmp = m1.m21(); m1._m21(m2.m21()); m2._m21(tmp);
+ tmp = m1.m22(); m1._m22(m2.m22()); m2._m22(tmp);
+ tmp = m1.m30(); m1._m30(m2.m30()); m2._m30(tmp);
+ tmp = m1.m31(); m1._m31(m2.m31()); m2._m31(tmp);
+ tmp = m1.m32(); m1._m32(m2.m32()); m2._m32(tmp);
+ }
+
+ public void swap(Matrix3f m1, Matrix3f m2) {
+ float tmp;
+ tmp = m1.m00(); m1._m00(m2.m00()); m2._m00(tmp);
+ tmp = m1.m01(); m1._m01(m2.m01()); m2._m01(tmp);
+ tmp = m1.m02(); m1._m02(m2.m02()); m2._m02(tmp);
+ tmp = m1.m10(); m1._m10(m2.m10()); m2._m10(tmp);
+ tmp = m1.m11(); m1._m11(m2.m11()); m2._m11(tmp);
+ tmp = m1.m12(); m1._m12(m2.m12()); m2._m12(tmp);
+ tmp = m1.m20(); m1._m20(m2.m20()); m2._m20(tmp);
+ tmp = m1.m21(); m1._m21(m2.m21()); m2._m21(tmp);
+ tmp = m1.m22(); m1._m22(m2.m22()); m2._m22(tmp);
+ }
+
+ public void swap(Matrix2f m1, Matrix2f m2) {
+ float tmp;
+ tmp = m1.m00(); m1._m00(m2.m00()); m2._m00(tmp);
+ tmp = m1.m01(); m1._m00(m2.m01()); m2._m01(tmp);
+ tmp = m1.m10(); m1._m00(m2.m10()); m2._m10(tmp);
+ tmp = m1.m11(); m1._m00(m2.m11()); m2._m11(tmp);
+ }
+
+ public void swap(Matrix2d m1, Matrix2d m2) {
+ double tmp;
+ tmp = m1.m00(); m1._m00(m2.m00()); m2._m00(tmp);
+ tmp = m1.m01(); m1._m00(m2.m01()); m2._m01(tmp);
+ tmp = m1.m10(); m1._m00(m2.m10()); m2._m10(tmp);
+ tmp = m1.m11(); m1._m00(m2.m11()); m2._m11(tmp);
+ }
+
+ public void zero(Matrix4f dest) {
+ dest._m00(0.0f)
+ ._m01(0.0f)
+ ._m02(0.0f)
+ ._m03(0.0f)
+ ._m10(0.0f)
+ ._m11(0.0f)
+ ._m12(0.0f)
+ ._m13(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(0.0f)
+ ._m23(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f)
+ ._m33(0.0f);
+ }
+
+ public void zero(Matrix4x3f dest) {
+ dest._m00(0.0f)
+ ._m01(0.0f)
+ ._m02(0.0f)
+ ._m10(0.0f)
+ ._m11(0.0f)
+ ._m12(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(0.0f)
+ ._m30(0.0f)
+ ._m31(0.0f)
+ ._m32(0.0f);
+ }
+
+ public void zero(Matrix3f dest) {
+ dest._m00(0.0f)
+ ._m01(0.0f)
+ ._m02(0.0f)
+ ._m10(0.0f)
+ ._m11(0.0f)
+ ._m12(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f)
+ ._m22(0.0f);
+ }
+
+ public void zero(Matrix3x2f dest) {
+ dest._m00(0.0f)
+ ._m01(0.0f)
+ ._m10(0.0f)
+ ._m11(0.0f)
+ ._m20(0.0f)
+ ._m21(0.0f);
+ }
+
+ public void zero(Matrix3x2d dest) {
+ dest._m00(0.0)
+ ._m01(0.0)
+ ._m10(0.0)
+ ._m11(0.0)
+ ._m20(0.0)
+ ._m21(0.0);
+ }
+
+ public void zero(Matrix2f dest) {
+ dest._m00(0.0f)
+ ._m01(0.0f)
+ ._m10(0.0f)
+ ._m11(0.0f);
+ }
+
+ public void zero(Matrix2d dest) {
+ dest._m00(0.0)
+ ._m01(0.0)
+ ._m10(0.0)
+ ._m11(0.0);
+ }
+
+ public void putMatrix3f(Quaternionf q, int position, ByteBuffer dest) {
+ float w2 = q.w * q.w;
+ float x2 = q.x * q.x;
+ float y2 = q.y * q.y;
+ float z2 = q.z * q.z;
+ float zw = q.z * q.w;
+ float xy = q.x * q.y;
+ float xz = q.x * q.z;
+ float yw = q.y * q.w;
+ float yz = q.y * q.z;
+ float xw = q.x * q.w;
+ dest.putFloat(position, w2 + x2 - z2 - y2)
+ .putFloat(position + 4, xy + zw + zw + xy)
+ .putFloat(position + 8, xz - yw + xz - yw)
+ .putFloat(position + 12, -zw + xy - zw + xy)
+ .putFloat(position + 16, y2 - z2 + w2 - x2)
+ .putFloat(position + 20, yz + yz + xw + xw)
+ .putFloat(position + 24, yw + xz + xz + yw)
+ .putFloat(position + 28, yz + yz - xw - xw)
+ .putFloat(position + 32, z2 - y2 - x2 + w2);
+ }
+
+ public void putMatrix3f(Quaternionf q, int position, FloatBuffer dest) {
+ float w2 = q.w * q.w;
+ float x2 = q.x * q.x;
+ float y2 = q.y * q.y;
+ float z2 = q.z * q.z;
+ float zw = q.z * q.w;
+ float xy = q.x * q.y;
+ float xz = q.x * q.z;
+ float yw = q.y * q.w;
+ float yz = q.y * q.z;
+ float xw = q.x * q.w;
+ dest.put(position, w2 + x2 - z2 - y2)
+ .put(position + 1, xy + zw + zw + xy)
+ .put(position + 2, xz - yw + xz - yw)
+ .put(position + 3, -zw + xy - zw + xy)
+ .put(position + 4, y2 - z2 + w2 - x2)
+ .put(position + 5, yz + yz + xw + xw)
+ .put(position + 6, yw + xz + xz + yw)
+ .put(position + 7, yz + yz - xw - xw)
+ .put(position + 8, z2 - y2 - x2 + w2);
+ }
+
+ public void putMatrix4f(Quaternionf q, int position, ByteBuffer dest) {
+ float w2 = q.w * q.w;
+ float x2 = q.x * q.x;
+ float y2 = q.y * q.y;
+ float z2 = q.z * q.z;
+ float zw = q.z * q.w;
+ float xy = q.x * q.y;
+ float xz = q.x * q.z;
+ float yw = q.y * q.w;
+ float yz = q.y * q.z;
+ float xw = q.x * q.w;
+ dest.putFloat(position, w2 + x2 - z2 - y2)
+ .putFloat(position + 4, xy + zw + zw + xy)
+ .putFloat(position + 8, xz - yw + xz - yw)
+ .putFloat(position + 12, 0.0f)
+ .putFloat(position + 16, -zw + xy - zw + xy)
+ .putFloat(position + 20, y2 - z2 + w2 - x2)
+ .putFloat(position + 24, yz + yz + xw + xw)
+ .putFloat(position + 28, 0.0f)
+ .putFloat(position + 32, yw + xz + xz + yw)
+ .putFloat(position + 36, yz + yz - xw - xw)
+ .putFloat(position + 40, z2 - y2 - x2 + w2)
+ .putFloat(position + 44, 0.0f)
+ .putLong(position + 48, 0L)
+ .putLong(position + 56, 0x3F80000000000000L);
+ }
+
+ public void putMatrix4f(Quaternionf q, int position, FloatBuffer dest) {
+ float w2 = q.w * q.w;
+ float x2 = q.x * q.x;
+ float y2 = q.y * q.y;
+ float z2 = q.z * q.z;
+ float zw = q.z * q.w;
+ float xy = q.x * q.y;
+ float xz = q.x * q.z;
+ float yw = q.y * q.w;
+ float yz = q.y * q.z;
+ float xw = q.x * q.w;
+ dest.put(position, w2 + x2 - z2 - y2)
+ .put(position + 1, xy + zw + zw + xy)
+ .put(position + 2, xz - yw + xz - yw)
+ .put(position + 3, 0.0f)
+ .put(position + 4, -zw + xy - zw + xy)
+ .put(position + 5, y2 - z2 + w2 - x2)
+ .put(position + 6, yz + yz + xw + xw)
+ .put(position + 7, 0.0f)
+ .put(position + 8, yw + xz + xz + yw)
+ .put(position + 9, yz + yz - xw - xw)
+ .put(position + 10, z2 - y2 - x2 + w2)
+ .put(position + 11, 0.0f)
+ .put(position + 12, 0.0f)
+ .put(position + 13, 0.0f)
+ .put(position + 14, 0.0f)
+ .put(position + 15, 1.0f);
+ }
+
+ public void putMatrix4x3f(Quaternionf q, int position, ByteBuffer dest) {
+ float w2 = q.w * q.w;
+ float x2 = q.x * q.x;
+ float y2 = q.y * q.y;
+ float z2 = q.z * q.z;
+ float zw = q.z * q.w;
+ float xy = q.x * q.y;
+ float xz = q.x * q.z;
+ float yw = q.y * q.w;
+ float yz = q.y * q.z;
+ float xw = q.x * q.w;
+ dest.putFloat(position, w2 + x2 - z2 - y2)
+ .putFloat(position + 4, xy + zw + zw + xy)
+ .putFloat(position + 8, xz - yw + xz - yw)
+ .putFloat(position + 12, -zw + xy - zw + xy)
+ .putFloat(position + 16, y2 - z2 + w2 - x2)
+ .putFloat(position + 20, yz + yz + xw + xw)
+ .putFloat(position + 24, yw + xz + xz + yw)
+ .putFloat(position + 28, yz + yz - xw - xw)
+ .putFloat(position + 32, z2 - y2 - x2 + w2)
+ .putLong(position + 36, 0L)
+ .putFloat(position + 44, 0.0f);
+ }
+
+ public void putMatrix4x3f(Quaternionf q, int position, FloatBuffer dest) {
+ float w2 = q.w * q.w;
+ float x2 = q.x * q.x;
+ float y2 = q.y * q.y;
+ float z2 = q.z * q.z;
+ float zw = q.z * q.w;
+ float xy = q.x * q.y;
+ float xz = q.x * q.z;
+ float yw = q.y * q.w;
+ float yz = q.y * q.z;
+ float xw = q.x * q.w;
+ dest.put(position, w2 + x2 - z2 - y2)
+ .put(position + 1, xy + zw + zw + xy)
+ .put(position + 2, xz - yw + xz - yw)
+ .put(position + 3, -zw + xy - zw + xy)
+ .put(position + 4, y2 - z2 + w2 - x2)
+ .put(position + 5, yz + yz + xw + xw)
+ .put(position + 6, yw + xz + xz + yw)
+ .put(position + 7, yz + yz - xw - xw)
+ .put(position + 8, z2 - y2 - x2 + w2)
+ .put(position + 9, 0.0f)
+ .put(position + 10, 0.0f)
+ .put(position + 11, 0.0f);
+ }
+ }
+
+ public static class MemUtilUnsafe extends MemUtilNIO {
+ public static final sun.misc.Unsafe UNSAFE;
+
+ public static final long ADDRESS;
+ public static final long Matrix2f_m00;
+ public static final long Matrix3f_m00;
+ public static final long Matrix3d_m00;
+ public static final long Matrix4f_m00;
+ public static final long Matrix4d_m00;
+ public static final long Matrix4x3f_m00;
+ public static final long Matrix3x2f_m00;
+ public static final long Vector4f_x;
+ public static final long Vector4i_x;
+ public static final long Vector3f_x;
+ public static final long Vector3i_x;
+ public static final long Vector2f_x;
+ public static final long Vector2i_x;
+ public static final long Quaternionf_x;
+ public static final long floatArrayOffset;
+
+ static {
+ UNSAFE = getUnsafeInstance();
+ try {
+ ADDRESS = findBufferAddress();
+ Matrix4f_m00 = checkMatrix4f();
+ Matrix4d_m00 = checkMatrix4d();
+ Matrix4x3f_m00 = checkMatrix4x3f();
+ Matrix3f_m00 = checkMatrix3f();
+ Matrix3d_m00 = checkMatrix3d();
+ Matrix3x2f_m00 = checkMatrix3x2f();
+ Matrix2f_m00 = checkMatrix2f();
+ Vector4f_x = checkVector4f();
+ Vector4i_x = checkVector4i();
+ Vector3f_x = checkVector3f();
+ Vector3i_x = checkVector3i();
+ Vector2f_x = checkVector2f();
+ Vector2i_x = checkVector2i();
+ Quaternionf_x = checkQuaternionf();
+ floatArrayOffset = UNSAFE.arrayBaseOffset(float[].class);
+ // Check if we can use object field offset/address put/get methods
+ sun.misc.Unsafe.class.getDeclaredMethod("getLong", new Class[] {Object.class, long.class});
+ sun.misc.Unsafe.class.getDeclaredMethod("putLong", new Class[] {Object.class, long.class, long.class});
+ } catch (NoSuchFieldException e) {
+ throw new UnsupportedOperationException(e);
+ } catch (NoSuchMethodException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ private static long findBufferAddress() {
+ try {
+ return UNSAFE.objectFieldOffset(getDeclaredField(Buffer.class, "address")); //$NON-NLS-1$
+ } catch (Exception e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ private static long checkMatrix4f() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix4f.class.getDeclaredField("m00");
+ long Matrix4f_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 16; i++) {
+ int c = i >>> 2;
+ int r = i & 3;
+ f = Matrix4f.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix4f_m00 + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Matrix4f element offset");
+ }
+ return Matrix4f_m00;
+ }
+
+ private static long checkMatrix4d() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix4d.class.getDeclaredField("m00");
+ long Matrix4d_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 16; i++) {
+ int c = i >>> 2;
+ int r = i & 3;
+ f = Matrix4d.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix4d_m00 + (i << 3))
+ throw new UnsupportedOperationException("Unexpected Matrix4d element offset");
+ }
+ return Matrix4d_m00;
+ }
+
+ private static long checkMatrix4x3f() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix4x3f.class.getDeclaredField("m00");
+ long Matrix4x3f_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 12; i++) {
+ int c = i / 3;
+ int r = i % 3;
+ f = Matrix4x3f.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix4x3f_m00 + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Matrix4x3f element offset");
+ }
+ return Matrix4x3f_m00;
+ }
+
+ private static long checkMatrix3f() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix3f.class.getDeclaredField("m00");
+ long Matrix3f_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 9; i++) {
+ int c = i / 3;
+ int r = i % 3;
+ f = Matrix3f.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix3f_m00 + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Matrix3f element offset");
+ }
+ return Matrix3f_m00;
+ }
+
+ private static long checkMatrix3d() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix3d.class.getDeclaredField("m00");
+ long Matrix3d_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 9; i++) {
+ int c = i / 3;
+ int r = i % 3;
+ f = Matrix3d.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix3d_m00 + (i << 3))
+ throw new UnsupportedOperationException("Unexpected Matrix3d element offset");
+ }
+ return Matrix3d_m00;
+ }
+
+ private static long checkMatrix3x2f() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix3x2f.class.getDeclaredField("m00");
+ long Matrix3x2f_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 6; i++) {
+ int c = i / 2;
+ int r = i % 2;
+ f = Matrix3x2f.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix3x2f_m00 + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Matrix3x2f element offset");
+ }
+ return Matrix3x2f_m00;
+ }
+
+ private static long checkMatrix2f() throws NoSuchFieldException, SecurityException {
+ Field f = Matrix2f.class.getDeclaredField("m00");
+ long Matrix2f_m00 = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ for (int i = 1; i < 4; i++) {
+ int c = i / 2;
+ int r = i % 2;
+ f = Matrix2f.class.getDeclaredField("m" + c + r);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Matrix2f_m00 + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Matrix2f element offset");
+ }
+ return Matrix2f_m00;
+ }
+
+ private static long checkVector4f() throws NoSuchFieldException, SecurityException {
+ Field f = Vector4f.class.getDeclaredField("x");
+ long Vector4f_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ String[] names = {"y", "z", "w"};
+ for (int i = 1; i < 4; i++) {
+ f = Vector4f.class.getDeclaredField(names[i-1]);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Vector4f_x + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Vector4f element offset");
+ }
+ return Vector4f_x;
+ }
+
+ private static long checkVector4i() throws NoSuchFieldException, SecurityException {
+ Field f = Vector4i.class.getDeclaredField("x");
+ long Vector4i_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ String[] names = {"y", "z", "w"};
+ for (int i = 1; i < 4; i++) {
+ f = Vector4i.class.getDeclaredField(names[i-1]);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Vector4i_x + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Vector4i element offset");
+ }
+ return Vector4i_x;
+ }
+
+ private static long checkVector3f() throws NoSuchFieldException, SecurityException {
+ Field f = Vector3f.class.getDeclaredField("x");
+ long Vector3f_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ String[] names = {"y", "z"};
+ for (int i = 1; i < 3; i++) {
+ f = Vector3f.class.getDeclaredField(names[i-1]);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Vector3f_x + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Vector3f element offset");
+ }
+ return Vector3f_x;
+ }
+
+ private static long checkVector3i() throws NoSuchFieldException, SecurityException {
+ Field f = Vector3i.class.getDeclaredField("x");
+ long Vector3i_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ String[] names = {"y", "z"};
+ for (int i = 1; i < 3; i++) {
+ f = Vector3i.class.getDeclaredField(names[i-1]);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Vector3i_x + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Vector3i element offset");
+ }
+ return Vector3i_x;
+ }
+
+ private static long checkVector2f() throws NoSuchFieldException, SecurityException {
+ Field f = Vector2f.class.getDeclaredField("x");
+ long Vector2f_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ f = Vector2f.class.getDeclaredField("y");
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Vector2f_x + (1 << 2))
+ throw new UnsupportedOperationException("Unexpected Vector2f element offset");
+ return Vector2f_x;
+ }
+
+ private static long checkVector2i() throws NoSuchFieldException, SecurityException {
+ Field f = Vector2i.class.getDeclaredField("x");
+ long Vector2i_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ f = Vector2i.class.getDeclaredField("y");
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Vector2i_x + (1 << 2))
+ throw new UnsupportedOperationException("Unexpected Vector2i element offset");
+ return Vector2i_x;
+ }
+
+ private static long checkQuaternionf() throws NoSuchFieldException, SecurityException {
+ Field f = Quaternionf.class.getDeclaredField("x");
+ long Quaternionf_x = UNSAFE.objectFieldOffset(f);
+ // Validate expected field offsets
+ String[] names = {"y", "z", "w"};
+ for (int i = 1; i < 4; i++) {
+ f = Quaternionf.class.getDeclaredField(names[i-1]);
+ long offset = UNSAFE.objectFieldOffset(f);
+ if (offset != Quaternionf_x + (i << 2))
+ throw new UnsupportedOperationException("Unexpected Quaternionf element offset");
+ }
+ return Quaternionf_x;
+ }
+
+ private static java.lang.reflect.Field getDeclaredField(Class root, String fieldName) throws NoSuchFieldException {
+ Class type = root;
+ do {
+ try {
+ java.lang.reflect.Field field = type.getDeclaredField(fieldName);
+ return field;
+ } catch (NoSuchFieldException e) {
+ type = type.getSuperclass();
+ } catch (SecurityException e) {
+ type = type.getSuperclass();
+ }
+ } while (type != null);
+ throw new NoSuchFieldException(fieldName + " does not exist in " + root.getName() + " or any of its superclasses."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public static sun.misc.Unsafe getUnsafeInstance() throws SecurityException {
+ java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ java.lang.reflect.Field field = fields[i];
+ if (!field.getType().equals(sun.misc.Unsafe.class))
+ continue;
+ int modifiers = field.getModifiers();
+ if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers)))
+ continue;
+ field.setAccessible(true);
+ try {
+ return (sun.misc.Unsafe) field.get(null);
+ } catch (IllegalAccessException e) {
+ /* Ignore */
+ }
+ break;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public static void put(Matrix4f m, long destAddr) {
+ for (int i = 0; i < 8; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 3), UNSAFE.getLong(m, Matrix4f_m00 + (i << 3)));
+ }
+ }
+
+ public static void put4x3(Matrix4f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ for (int i = 0; i < 4; i++) {
+ u.putLong(null, destAddr + 12 * i, u.getLong(m, Matrix4f_m00 + (i << 4)));
+ }
+ u.putFloat(null, destAddr + 8, m.m02());
+ u.putFloat(null, destAddr + 20, m.m12());
+ u.putFloat(null, destAddr + 32, m.m22());
+ u.putFloat(null, destAddr + 44, m.m32());
+ }
+
+ public static void put3x4(Matrix4f m, long destAddr) {
+ for (int i = 0; i < 6; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 3), UNSAFE.getLong(m, Matrix4f_m00 + (i << 3)));
+ }
+ }
+
+ public static void put(Matrix4x3f m, long destAddr) {
+ for (int i = 0; i < 6; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 3), UNSAFE.getLong(m, Matrix4x3f_m00 + (i << 3)));
+ }
+ }
+
+ public static void put4x4(Matrix4x3f m, long destAddr) {
+ for (int i = 0; i < 4; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 4), UNSAFE.getLong(m, Matrix4x3f_m00 + 12 * i));
+ long lng = UNSAFE.getInt(m, Matrix4x3f_m00 + 8 + 12 * i) & 0xFFFFFFFFL;
+ UNSAFE.putLong(null, destAddr + 8 + (i << 4), lng);
+ }
+ UNSAFE.putFloat(null, destAddr + 60, 1.0f);
+ }
+
+ public static void put3x4(Matrix4x3f m, long destAddr) {
+ for (int i = 0; i < 3; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 4), UNSAFE.getLong(m, Matrix4x3f_m00 + 12 * i));
+ UNSAFE.putFloat(null, destAddr + (i << 4) + 8, UNSAFE.getFloat(m, Matrix4x3f_m00 + 8 + 12 * i));
+ UNSAFE.putFloat(null, destAddr + (i << 4) + 12, 0.0f);
+ }
+ }
+
+ public static void put4x4(Matrix4x3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, m.m02());
+ u.putDouble(null, destAddr + 24, 0.0);
+ u.putDouble(null, destAddr + 32, m.m10());
+ u.putDouble(null, destAddr + 40, m.m11());
+ u.putDouble(null, destAddr + 48, m.m12());
+ u.putDouble(null, destAddr + 56, 0.0);
+ u.putDouble(null, destAddr + 64, m.m20());
+ u.putDouble(null, destAddr + 72, m.m21());
+ u.putDouble(null, destAddr + 80, m.m22());
+ u.putDouble(null, destAddr + 88, 0.0);
+ u.putDouble(null, destAddr + 96, m.m30());
+ u.putDouble(null, destAddr + 104, m.m31());
+ u.putDouble(null, destAddr + 112, m.m32());
+ u.putDouble(null, destAddr + 120, 1.0);
+ }
+
+ public static void put4x4(Matrix3x2f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putLong(null, destAddr, u.getLong(m, Matrix3x2f_m00));
+ u.putLong(null, destAddr+8, 0L);
+ u.putLong(null, destAddr+16, u.getLong(m, Matrix3x2f_m00+8));
+ u.putLong(null, destAddr+24, 0L);
+ u.putLong(null, destAddr+32, 0L);
+ u.putLong(null, destAddr+40, 0x3F800000L);
+ u.putLong(null, destAddr+48, u.getLong(m, Matrix3x2f_m00+16));
+ u.putLong(null, destAddr+56, 0x3F80000000000000L);
+ }
+
+ public static void put4x4(Matrix3x2d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, 0.0);
+ u.putDouble(null, destAddr + 24, 0.0);
+ u.putDouble(null, destAddr + 32, m.m10());
+ u.putDouble(null, destAddr + 40, m.m11());
+ u.putDouble(null, destAddr + 48, 0.0);
+ u.putDouble(null, destAddr + 56, 0.0);
+ u.putDouble(null, destAddr + 64, 0.0);
+ u.putDouble(null, destAddr + 72, 0.0);
+ u.putDouble(null, destAddr + 80, 1.0);
+ u.putDouble(null, destAddr + 88, 0.0);
+ u.putDouble(null, destAddr + 96, m.m20());
+ u.putDouble(null, destAddr + 104, m.m21());
+ u.putDouble(null, destAddr + 112, 0.0);
+ u.putDouble(null, destAddr + 120, 1.0);
+ }
+
+ public static void put3x3(Matrix3x2f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putLong( null, destAddr, u.getLong(m, Matrix3x2f_m00));
+ u.putInt( null, destAddr+8, 0);
+ u.putLong( null, destAddr+12, u.getLong(m, Matrix3x2f_m00+8));
+ u.putInt( null, destAddr+20, 0);
+ u.putLong( null, destAddr+24, u.getLong(m, Matrix3x2f_m00+16));
+ u.putFloat(null, destAddr+32, 1.0f);
+ }
+
+ public static void put3x3(Matrix3x2d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, 0.0);
+ u.putDouble(null, destAddr + 24, m.m10());
+ u.putDouble(null, destAddr + 32, m.m11());
+ u.putDouble(null, destAddr + 40, 0.0);
+ u.putDouble(null, destAddr + 48, m.m20());
+ u.putDouble(null, destAddr + 56, m.m21());
+ u.putDouble(null, destAddr + 64, 1.0);
+ }
+
+ public static void putTransposed(Matrix4f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, m.m00());
+ u.putFloat(null, destAddr + 4, m.m10());
+ u.putFloat(null, destAddr + 8, m.m20());
+ u.putFloat(null, destAddr + 12, m.m30());
+ u.putFloat(null, destAddr + 16, m.m01());
+ u.putFloat(null, destAddr + 20, m.m11());
+ u.putFloat(null, destAddr + 24, m.m21());
+ u.putFloat(null, destAddr + 28, m.m31());
+ u.putFloat(null, destAddr + 32, m.m02());
+ u.putFloat(null, destAddr + 36, m.m12());
+ u.putFloat(null, destAddr + 40, m.m22());
+ u.putFloat(null, destAddr + 44, m.m32());
+ u.putFloat(null, destAddr + 48, m.m03());
+ u.putFloat(null, destAddr + 52, m.m13());
+ u.putFloat(null, destAddr + 56, m.m23());
+ u.putFloat(null, destAddr + 60, m.m33());
+ }
+
+ public static void put4x3Transposed(Matrix4f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, m.m00());
+ u.putFloat(null, destAddr + 4, m.m10());
+ u.putFloat(null, destAddr + 8, m.m20());
+ u.putFloat(null, destAddr + 12, m.m30());
+ u.putFloat(null, destAddr + 16, m.m01());
+ u.putFloat(null, destAddr + 20, m.m11());
+ u.putFloat(null, destAddr + 24, m.m21());
+ u.putFloat(null, destAddr + 28, m.m31());
+ u.putFloat(null, destAddr + 32, m.m02());
+ u.putFloat(null, destAddr + 36, m.m12());
+ u.putFloat(null, destAddr + 40, m.m22());
+ u.putFloat(null, destAddr + 44, m.m32());
+ }
+
+ public static void putTransposed(Matrix4x3f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, m.m00());
+ u.putFloat(null, destAddr + 4, m.m10());
+ u.putFloat(null, destAddr + 8, m.m20());
+ u.putFloat(null, destAddr + 12, m.m30());
+ u.putFloat(null, destAddr + 16, m.m01());
+ u.putFloat(null, destAddr + 20, m.m11());
+ u.putFloat(null, destAddr + 24, m.m21());
+ u.putFloat(null, destAddr + 28, m.m31());
+ u.putFloat(null, destAddr + 32, m.m02());
+ u.putFloat(null, destAddr + 36, m.m12());
+ u.putFloat(null, destAddr + 40, m.m22());
+ u.putFloat(null, destAddr + 44, m.m32());
+ }
+
+ public static void putTransposed(Matrix3f m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, m.m00());
+ u.putFloat(null, destAddr + 4, m.m10());
+ u.putFloat(null, destAddr + 8, m.m20());
+ u.putFloat(null, destAddr + 12, m.m01());
+ u.putFloat(null, destAddr + 16, m.m11());
+ u.putFloat(null, destAddr + 20, m.m21());
+ u.putFloat(null, destAddr + 24, m.m02());
+ u.putFloat(null, destAddr + 28, m.m12());
+ u.putFloat(null, destAddr + 32, m.m22());
+ }
+
+ public static void putTransposed(Matrix2f m, long destAddr) {
+ UNSAFE.putFloat(null, destAddr, m.m00());
+ UNSAFE.putFloat(null, destAddr + 4, m.m10());
+ UNSAFE.putFloat(null, destAddr + 8, m.m01());
+ UNSAFE.putFloat(null, destAddr + 12, m.m11());
+ }
+
+ public static void put(Matrix4d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, m.m02());
+ u.putDouble(null, destAddr + 24, m.m03());
+ u.putDouble(null, destAddr + 32, m.m10());
+ u.putDouble(null, destAddr + 40, m.m11());
+ u.putDouble(null, destAddr + 48, m.m12());
+ u.putDouble(null, destAddr + 56, m.m13());
+ u.putDouble(null, destAddr + 64, m.m20());
+ u.putDouble(null, destAddr + 72, m.m21());
+ u.putDouble(null, destAddr + 80, m.m22());
+ u.putDouble(null, destAddr + 88, m.m23());
+ u.putDouble(null, destAddr + 96, m.m30());
+ u.putDouble(null, destAddr + 104, m.m31());
+ u.putDouble(null, destAddr + 112, m.m32());
+ u.putDouble(null, destAddr + 120, m.m33());
+ }
+
+ public static void put(Matrix4x3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, m.m02());
+ u.putDouble(null, destAddr + 24, m.m10());
+ u.putDouble(null, destAddr + 32, m.m11());
+ u.putDouble(null, destAddr + 40, m.m12());
+ u.putDouble(null, destAddr + 48, m.m20());
+ u.putDouble(null, destAddr + 56, m.m21());
+ u.putDouble(null, destAddr + 64, m.m22());
+ u.putDouble(null, destAddr + 72, m.m30());
+ u.putDouble(null, destAddr + 80, m.m31());
+ u.putDouble(null, destAddr + 88, m.m32());
+ }
+
+ public static void putTransposed(Matrix4d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m10());
+ u.putDouble(null, destAddr + 16, m.m20());
+ u.putDouble(null, destAddr + 24, m.m30());
+ u.putDouble(null, destAddr + 32, m.m01());
+ u.putDouble(null, destAddr + 40, m.m11());
+ u.putDouble(null, destAddr + 48, m.m21());
+ u.putDouble(null, destAddr + 56, m.m31());
+ u.putDouble(null, destAddr + 64, m.m02());
+ u.putDouble(null, destAddr + 72, m.m12());
+ u.putDouble(null, destAddr + 80, m.m22());
+ u.putDouble(null, destAddr + 88, m.m32());
+ u.putDouble(null, destAddr + 96, m.m03());
+ u.putDouble(null, destAddr + 104, m.m13());
+ u.putDouble(null, destAddr + 112, m.m23());
+ u.putDouble(null, destAddr + 120, m.m33());
+ }
+
+ public static void putfTransposed(Matrix4d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, (float)m.m00());
+ u.putFloat(null, destAddr + 4, (float)m.m10());
+ u.putFloat(null, destAddr + 8, (float)m.m20());
+ u.putFloat(null, destAddr + 12, (float)m.m30());
+ u.putFloat(null, destAddr + 16, (float)m.m01());
+ u.putFloat(null, destAddr + 20, (float)m.m11());
+ u.putFloat(null, destAddr + 24, (float)m.m21());
+ u.putFloat(null, destAddr + 28, (float)m.m31());
+ u.putFloat(null, destAddr + 32, (float)m.m02());
+ u.putFloat(null, destAddr + 36, (float)m.m12());
+ u.putFloat(null, destAddr + 40, (float)m.m22());
+ u.putFloat(null, destAddr + 44, (float)m.m32());
+ u.putFloat(null, destAddr + 48, (float)m.m03());
+ u.putFloat(null, destAddr + 52, (float)m.m13());
+ u.putFloat(null, destAddr + 56, (float)m.m23());
+ u.putFloat(null, destAddr + 60, (float)m.m33());
+ }
+
+ public static void put4x3Transposed(Matrix4d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m10());
+ u.putDouble(null, destAddr + 16, m.m20());
+ u.putDouble(null, destAddr + 24, m.m30());
+ u.putDouble(null, destAddr + 32, m.m01());
+ u.putDouble(null, destAddr + 40, m.m11());
+ u.putDouble(null, destAddr + 48, m.m21());
+ u.putDouble(null, destAddr + 56, m.m31());
+ u.putDouble(null, destAddr + 64, m.m02());
+ u.putDouble(null, destAddr + 72, m.m12());
+ u.putDouble(null, destAddr + 80, m.m22());
+ u.putDouble(null, destAddr + 88, m.m32());
+ }
+
+ public static void putTransposed(Matrix4x3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m10());
+ u.putDouble(null, destAddr + 16, m.m20());
+ u.putDouble(null, destAddr + 24, m.m30());
+ u.putDouble(null, destAddr + 32, m.m01());
+ u.putDouble(null, destAddr + 40, m.m11());
+ u.putDouble(null, destAddr + 48, m.m21());
+ u.putDouble(null, destAddr + 56, m.m31());
+ u.putDouble(null, destAddr + 64, m.m02());
+ u.putDouble(null, destAddr + 72, m.m12());
+ u.putDouble(null, destAddr + 80, m.m22());
+ u.putDouble(null, destAddr + 88, m.m32());
+ }
+
+ public static void putTransposed(Matrix2d m, long destAddr) {
+ UNSAFE.putDouble(null, destAddr, m.m00());
+ UNSAFE.putDouble(null, destAddr + 8, m.m10());
+ UNSAFE.putDouble(null, destAddr + 16, m.m10());
+ UNSAFE.putDouble(null, destAddr + 24, m.m10());
+ }
+
+ public static void putfTransposed(Matrix4x3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, (float)m.m00());
+ u.putFloat(null, destAddr + 4, (float)m.m10());
+ u.putFloat(null, destAddr + 8, (float)m.m20());
+ u.putFloat(null, destAddr + 12, (float)m.m30());
+ u.putFloat(null, destAddr + 16, (float)m.m01());
+ u.putFloat(null, destAddr + 20, (float)m.m11());
+ u.putFloat(null, destAddr + 24, (float)m.m21());
+ u.putFloat(null, destAddr + 28, (float)m.m31());
+ u.putFloat(null, destAddr + 32, (float)m.m02());
+ u.putFloat(null, destAddr + 36, (float)m.m12());
+ u.putFloat(null, destAddr + 40, (float)m.m22());
+ u.putFloat(null, destAddr + 44, (float)m.m32());
+ }
+
+ public static void putfTransposed(Matrix2d m, long destAddr) {
+ UNSAFE.putFloat(null, destAddr, (float)m.m00());
+ UNSAFE.putFloat(null, destAddr + 4, (float)m.m00());
+ UNSAFE.putFloat(null, destAddr + 8, (float)m.m00());
+ UNSAFE.putFloat(null, destAddr + 12, (float)m.m00());
+ }
+
+ public static void putf(Matrix4d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, (float)m.m00());
+ u.putFloat(null, destAddr + 4, (float)m.m01());
+ u.putFloat(null, destAddr + 8, (float)m.m02());
+ u.putFloat(null, destAddr + 12, (float)m.m03());
+ u.putFloat(null, destAddr + 16, (float)m.m10());
+ u.putFloat(null, destAddr + 20, (float)m.m11());
+ u.putFloat(null, destAddr + 24, (float)m.m12());
+ u.putFloat(null, destAddr + 28, (float)m.m13());
+ u.putFloat(null, destAddr + 32, (float)m.m20());
+ u.putFloat(null, destAddr + 36, (float)m.m21());
+ u.putFloat(null, destAddr + 40, (float)m.m22());
+ u.putFloat(null, destAddr + 44, (float)m.m23());
+ u.putFloat(null, destAddr + 48, (float)m.m30());
+ u.putFloat(null, destAddr + 52, (float)m.m31());
+ u.putFloat(null, destAddr + 56, (float)m.m32());
+ u.putFloat(null, destAddr + 60, (float)m.m33());
+ }
+
+ public static void putf(Matrix4x3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, (float)m.m00());
+ u.putFloat(null, destAddr + 4, (float)m.m01());
+ u.putFloat(null, destAddr + 8, (float)m.m02());
+ u.putFloat(null, destAddr + 12, (float)m.m10());
+ u.putFloat(null, destAddr + 16, (float)m.m11());
+ u.putFloat(null, destAddr + 20, (float)m.m12());
+ u.putFloat(null, destAddr + 24, (float)m.m20());
+ u.putFloat(null, destAddr + 28, (float)m.m21());
+ u.putFloat(null, destAddr + 32, (float)m.m22());
+ u.putFloat(null, destAddr + 36, (float)m.m30());
+ u.putFloat(null, destAddr + 40, (float)m.m31());
+ u.putFloat(null, destAddr + 44, (float)m.m32());
+ }
+
+ public static void put(Matrix3f m, long destAddr) {
+ for (int i = 0; i < 4; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 3), UNSAFE.getLong(m, Matrix3f_m00 + (i << 3)));
+ }
+ UNSAFE.putFloat(null, destAddr + 32, m.m22());
+ }
+
+ public static void put3x4(Matrix3f m, long destAddr) {
+ for (int i = 0; i < 3; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 4), UNSAFE.getLong(m, Matrix3f_m00 + 12 * i));
+ UNSAFE.putFloat(null, destAddr + (i << 4) + 8, UNSAFE.getFloat(m, Matrix3f_m00 + 8 + 12 * i));
+ UNSAFE.putFloat(null, destAddr + 12 * i, 0.0f);
+ }
+ }
+
+ public static void put(Matrix3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, m.m02());
+ u.putDouble(null, destAddr + 24, m.m10());
+ u.putDouble(null, destAddr + 32, m.m11());
+ u.putDouble(null, destAddr + 40, m.m12());
+ u.putDouble(null, destAddr + 48, m.m20());
+ u.putDouble(null, destAddr + 56, m.m21());
+ u.putDouble(null, destAddr + 64, m.m22());
+ }
+
+ public static void put(Matrix3x2f m, long destAddr) {
+ for (int i = 0; i < 3; i++) {
+ UNSAFE.putLong(null, destAddr + (i << 3), UNSAFE.getLong(m, Matrix3x2f_m00 + (i << 3)));
+ }
+ }
+
+ public static void put(Matrix3x2d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putDouble(null, destAddr, m.m00());
+ u.putDouble(null, destAddr + 8, m.m01());
+ u.putDouble(null, destAddr + 16, m.m10());
+ u.putDouble(null, destAddr + 24, m.m11());
+ u.putDouble(null, destAddr + 32, m.m20());
+ u.putDouble(null, destAddr + 40, m.m21());
+ }
+
+ public static void putf(Matrix3d m, long destAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, destAddr, (float)m.m00());
+ u.putFloat(null, destAddr + 4, (float)m.m01());
+ u.putFloat(null, destAddr + 8, (float)m.m02());
+ u.putFloat(null, destAddr + 12, (float)m.m10());
+ u.putFloat(null, destAddr + 16, (float)m.m11());
+ u.putFloat(null, destAddr + 20, (float)m.m12());
+ u.putFloat(null, destAddr + 24, (float)m.m20());
+ u.putFloat(null, destAddr + 28, (float)m.m21());
+ u.putFloat(null, destAddr + 32, (float)m.m22());
+ }
+
+ public static void put(Matrix2f m, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(m, Matrix2f_m00));
+ UNSAFE.putLong(null, destAddr + 8, UNSAFE.getLong(m, Matrix2f_m00 + 8));
+ }
+
+ public static void put(Matrix2d m, long destAddr) {
+ UNSAFE.putDouble(null, destAddr, m.m00());
+ UNSAFE.putDouble(null, destAddr + 8, m.m01());
+ UNSAFE.putDouble(null, destAddr + 16, m.m10());
+ UNSAFE.putDouble(null, destAddr + 24, m.m11());
+ }
+
+ public static void putf(Matrix2d m, long destAddr) {
+ UNSAFE.putFloat(null, destAddr, (float)m.m00());
+ UNSAFE.putFloat(null, destAddr + 4, (float)m.m01());
+ UNSAFE.putFloat(null, destAddr + 8, (float)m.m10());
+ UNSAFE.putFloat(null, destAddr + 12, (float)m.m11());
+ }
+
+ public static void put(Vector4d src, long destAddr) {
+ UNSAFE.putDouble(null, destAddr, src.x);
+ UNSAFE.putDouble(null, destAddr+8, src.y);
+ UNSAFE.putDouble(null, destAddr+16, src.z);
+ UNSAFE.putDouble(null, destAddr+24, src.w);
+ }
+
+ public static void putf(Vector4d src, long destAddr) {
+ UNSAFE.putFloat(null, destAddr, (float) src.x);
+ UNSAFE.putFloat(null, destAddr+4, (float) src.y);
+ UNSAFE.putFloat(null, destAddr+8, (float) src.z);
+ UNSAFE.putFloat(null, destAddr+12, (float) src.w);
+ }
+
+ public static void put(Vector4f src, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(src, Vector4f_x));
+ UNSAFE.putLong(null, destAddr+8, UNSAFE.getLong(src, Vector4f_x+8));
+ }
+
+ public static void put(Vector4i src, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(src, Vector4i_x));
+ UNSAFE.putLong(null, destAddr+8, UNSAFE.getLong(src, Vector4i_x+8));
+ }
+
+ public static void put(Vector3f src, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(src, Vector3f_x));
+ UNSAFE.putFloat(null, destAddr+8, src.z);
+ }
+
+ public static void put(Vector3d src, long destAddr) {
+ UNSAFE.putDouble(null, destAddr, src.x);
+ UNSAFE.putDouble(null, destAddr+8, src.y);
+ UNSAFE.putDouble(null, destAddr+16, src.z);
+ }
+
+ public static void putf(Vector3d src, long destAddr) {
+ UNSAFE.putFloat(null, destAddr, (float) src.x);
+ UNSAFE.putFloat(null, destAddr+4, (float) src.y);
+ UNSAFE.putFloat(null, destAddr+8, (float) src.z);
+ }
+
+ public static void put(Vector3i src, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(src, Vector3i_x));
+ UNSAFE.putInt(null, destAddr+8, src.z);
+ }
+
+ public static void put(Vector2f src, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(src, Vector2f_x));
+ }
+
+ public static void put(Vector2d src, long destAddr) {
+ UNSAFE.putDouble(null, destAddr, src.x);
+ UNSAFE.putDouble(null, destAddr+8, src.y);
+ }
+
+ public static void put(Vector2i src, long destAddr) {
+ UNSAFE.putLong(null, destAddr, UNSAFE.getLong(src, Vector2i_x));
+ }
+
+ public static void get(Matrix4f m, long srcAddr) {
+ for (int i = 0; i < 8; i++) {
+ UNSAFE.putLong(m, Matrix4f_m00 + (i << 3), UNSAFE.getLong(srcAddr + (i << 3)));
+ }
+ }
+
+ public static void getTransposed(Matrix4f m, long srcAddr) {
+ m._m00(UNSAFE.getFloat(srcAddr))
+ ._m10(UNSAFE.getFloat(srcAddr + 4))
+ ._m20(UNSAFE.getFloat(srcAddr + 8))
+ ._m30(UNSAFE.getFloat(srcAddr + 12))
+ ._m01(UNSAFE.getFloat(srcAddr + 16))
+ ._m11(UNSAFE.getFloat(srcAddr + 20))
+ ._m21(UNSAFE.getFloat(srcAddr + 24))
+ ._m31(UNSAFE.getFloat(srcAddr + 28))
+ ._m02(UNSAFE.getFloat(srcAddr + 32))
+ ._m12(UNSAFE.getFloat(srcAddr + 36))
+ ._m22(UNSAFE.getFloat(srcAddr + 40))
+ ._m32(UNSAFE.getFloat(srcAddr + 44))
+ ._m03(UNSAFE.getFloat(srcAddr + 48))
+ ._m13(UNSAFE.getFloat(srcAddr + 52))
+ ._m23(UNSAFE.getFloat(srcAddr + 56))
+ ._m33(UNSAFE.getFloat(srcAddr + 60));
+ }
+
+ public static void get(Matrix4x3f m, long srcAddr) {
+ for (int i = 0; i < 6; i++) {
+ UNSAFE.putLong(m, Matrix4x3f_m00 + (i << 3), UNSAFE.getLong(srcAddr + (i << 3)));
+ }
+ }
+
+ public static void get(Matrix4d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getDouble(null, srcAddr))
+ ._m01(u.getDouble(null, srcAddr+8))
+ ._m02(u.getDouble(null, srcAddr+16))
+ ._m03(u.getDouble(null, srcAddr+24))
+ ._m10(u.getDouble(null, srcAddr+32))
+ ._m11(u.getDouble(null, srcAddr+40))
+ ._m12(u.getDouble(null, srcAddr+48))
+ ._m13(u.getDouble(null, srcAddr+56))
+ ._m20(u.getDouble(null, srcAddr+64))
+ ._m21(u.getDouble(null, srcAddr+72))
+ ._m22(u.getDouble(null, srcAddr+80))
+ ._m23(u.getDouble(null, srcAddr+88))
+ ._m30(u.getDouble(null, srcAddr+96))
+ ._m31(u.getDouble(null, srcAddr+104))
+ ._m32(u.getDouble(null, srcAddr+112))
+ ._m33(u.getDouble(null, srcAddr+120));
+ }
+
+ public static void get(Matrix4x3d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getDouble(null, srcAddr))
+ ._m01(u.getDouble(null, srcAddr+8))
+ ._m02(u.getDouble(null, srcAddr+16))
+ ._m10(u.getDouble(null, srcAddr+24))
+ ._m11(u.getDouble(null, srcAddr+32))
+ ._m12(u.getDouble(null, srcAddr+40))
+ ._m20(u.getDouble(null, srcAddr+48))
+ ._m21(u.getDouble(null, srcAddr+56))
+ ._m22(u.getDouble(null, srcAddr+64))
+ ._m30(u.getDouble(null, srcAddr+72))
+ ._m31(u.getDouble(null, srcAddr+80))
+ ._m32(u.getDouble(null, srcAddr+88));
+ }
+
+ public static void getf(Matrix4d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getFloat(null, srcAddr))
+ ._m01(u.getFloat(null, srcAddr+4))
+ ._m02(u.getFloat(null, srcAddr+8))
+ ._m03(u.getFloat(null, srcAddr+12))
+ ._m10(u.getFloat(null, srcAddr+16))
+ ._m11(u.getFloat(null, srcAddr+20))
+ ._m12(u.getFloat(null, srcAddr+24))
+ ._m13(u.getFloat(null, srcAddr+28))
+ ._m20(u.getFloat(null, srcAddr+32))
+ ._m21(u.getFloat(null, srcAddr+36))
+ ._m22(u.getFloat(null, srcAddr+40))
+ ._m23(u.getFloat(null, srcAddr+44))
+ ._m30(u.getFloat(null, srcAddr+48))
+ ._m31(u.getFloat(null, srcAddr+52))
+ ._m32(u.getFloat(null, srcAddr+56))
+ ._m33(u.getFloat(null, srcAddr+60));
+ }
+
+ public static void getf(Matrix4x3d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getFloat(null, srcAddr))
+ ._m01(u.getFloat(null, srcAddr+4))
+ ._m02(u.getFloat(null, srcAddr+8))
+ ._m10(u.getFloat(null, srcAddr+12))
+ ._m11(u.getFloat(null, srcAddr+16))
+ ._m12(u.getFloat(null, srcAddr+20))
+ ._m20(u.getFloat(null, srcAddr+24))
+ ._m21(u.getFloat(null, srcAddr+28))
+ ._m22(u.getFloat(null, srcAddr+32))
+ ._m30(u.getFloat(null, srcAddr+36))
+ ._m31(u.getFloat(null, srcAddr+40))
+ ._m32(u.getFloat(null, srcAddr+44));
+ }
+
+ public static void get(Matrix3f m, long srcAddr) {
+ for (int i = 0; i < 4; i++) {
+ UNSAFE.putLong(m, Matrix3f_m00 + (i << 3), UNSAFE.getLong(null, srcAddr + (i << 3)));
+ }
+ m._m22(UNSAFE.getFloat(null, srcAddr+32));
+ }
+
+ public static void get(Matrix3d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getDouble(null, srcAddr))
+ ._m01(u.getDouble(null, srcAddr+8))
+ ._m02(u.getDouble(null, srcAddr+16))
+ ._m10(u.getDouble(null, srcAddr+24))
+ ._m11(u.getDouble(null, srcAddr+32))
+ ._m12(u.getDouble(null, srcAddr+40))
+ ._m20(u.getDouble(null, srcAddr+48))
+ ._m21(u.getDouble(null, srcAddr+56))
+ ._m22(u.getDouble(null, srcAddr+64));
+ }
+
+ public static void get(Matrix3x2f m, long srcAddr) {
+ for (int i = 0; i < 3; i++) {
+ UNSAFE.putLong(m, Matrix3x2f_m00 + (i << 3), UNSAFE.getLong(null, srcAddr + (i << 3)));
+ }
+ }
+
+ public static void get(Matrix3x2d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getDouble(null, srcAddr))
+ ._m01(u.getDouble(null, srcAddr+8))
+ ._m10(u.getDouble(null, srcAddr+16))
+ ._m11(u.getDouble(null, srcAddr+24))
+ ._m20(u.getDouble(null, srcAddr+32))
+ ._m21(u.getDouble(null, srcAddr+40));
+ }
+
+ public static void getf(Matrix3d m, long srcAddr) {
+ sun.misc.Unsafe u = UNSAFE;
+ m._m00(u.getFloat(null, srcAddr))
+ ._m01(u.getFloat(null, srcAddr+4))
+ ._m02(u.getFloat(null, srcAddr+8))
+ ._m10(u.getFloat(null, srcAddr+12))
+ ._m11(u.getFloat(null, srcAddr+16))
+ ._m12(u.getFloat(null, srcAddr+20))
+ ._m20(u.getFloat(null, srcAddr+24))
+ ._m21(u.getFloat(null, srcAddr+28))
+ ._m22(u.getFloat(null, srcAddr+32));
+ }
+
+ public static void get(Matrix2f m, long srcAddr) {
+ UNSAFE.putLong(m, Matrix2f_m00, UNSAFE.getLong(null, srcAddr));
+ UNSAFE.putLong(m, Matrix2f_m00 + 8, UNSAFE.getLong(null, srcAddr + 8));
+ }
+
+ public static void get(Matrix2d m, long srcAddr) {
+ m._m00(UNSAFE.getDouble(null, srcAddr))
+ ._m01(UNSAFE.getDouble(null, srcAddr+8))
+ ._m10(UNSAFE.getDouble(null, srcAddr+16))
+ ._m11(UNSAFE.getDouble(null, srcAddr+24));
+ }
+
+ public static void getf(Matrix2d m, long srcAddr) {
+ m._m00(UNSAFE.getFloat(null, srcAddr))
+ ._m01(UNSAFE.getFloat(null, srcAddr+4))
+ ._m10(UNSAFE.getFloat(null, srcAddr+8))
+ ._m11(UNSAFE.getFloat(null, srcAddr+12));
+ }
+
+ public static void get(Vector4d dst, long srcAddr) {
+ dst.x = UNSAFE.getDouble(null, srcAddr);
+ dst.y = UNSAFE.getDouble(null, srcAddr+8);
+ dst.z = UNSAFE.getDouble(null, srcAddr+16);
+ dst.w = UNSAFE.getDouble(null, srcAddr+24);
+ }
+
+ public static void get(Vector4f dst, long srcAddr) {
+ dst.x = UNSAFE.getFloat(null, srcAddr);
+ dst.y = UNSAFE.getFloat(null, srcAddr+4);
+ dst.z = UNSAFE.getFloat(null, srcAddr+8);
+ dst.w = UNSAFE.getFloat(null, srcAddr+12);
+ }
+
+ public static void get(Vector4i dst, long srcAddr) {
+ dst.x = UNSAFE.getInt(null, srcAddr);
+ dst.y = UNSAFE.getInt(null, srcAddr+4);
+ dst.z = UNSAFE.getInt(null, srcAddr+8);
+ dst.w = UNSAFE.getInt(null, srcAddr+12);
+ }
+
+ public static void get(Vector3f dst, long srcAddr) {
+ dst.x = UNSAFE.getFloat(null, srcAddr);
+ dst.y = UNSAFE.getFloat(null, srcAddr+4);
+ dst.z = UNSAFE.getFloat(null, srcAddr+8);
+ }
+
+ public static void get(Vector3d dst, long srcAddr) {
+ dst.x = UNSAFE.getDouble(null, srcAddr);
+ dst.y = UNSAFE.getDouble(null, srcAddr+8);
+ dst.z = UNSAFE.getDouble(null, srcAddr+16);
+ }
+
+ public static void get(Vector3i dst, long srcAddr) {
+ dst.x = UNSAFE.getInt(null, srcAddr);
+ dst.y = UNSAFE.getInt(null, srcAddr+4);
+ dst.z = UNSAFE.getInt(null, srcAddr+8);
+ }
+
+ public static void get(Vector2f dst, long srcAddr) {
+ dst.x = UNSAFE.getFloat(null, srcAddr);
+ dst.y = UNSAFE.getFloat(null, srcAddr+4);
+ }
+
+ public static void get(Vector2d dst, long srcAddr) {
+ dst.x = UNSAFE.getDouble(null, srcAddr);
+ dst.y = UNSAFE.getDouble(null, srcAddr+8);
+ }
+
+ public static void get(Vector2i dst, long srcAddr) {
+ dst.x = UNSAFE.getInt(null, srcAddr);
+ dst.y = UNSAFE.getInt(null, srcAddr+4);
+ }
+
+ public static void putMatrix3f(Quaternionf q, long addr) {
+ float dx = q.x + q.x;
+ float dy = q.y + q.y;
+ float dz = q.z + q.z;
+ float q00 = dx * q.x;
+ float q11 = dy * q.y;
+ float q22 = dz * q.z;
+ float q01 = dx * q.y;
+ float q02 = dx * q.z;
+ float q03 = dx * q.w;
+ float q12 = dy * q.z;
+ float q13 = dy * q.w;
+ float q23 = dz * q.w;
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, addr, 1.0f - q11 - q22);
+ u.putFloat(null, addr + 4, q01 + q23);
+ u.putFloat(null, addr + 8, q02 - q13);
+ u.putFloat(null, addr + 12, q01 - q23);
+ u.putFloat(null, addr + 16, 1.0f - q22 - q00);
+ u.putFloat(null, addr + 20, q12 + q03);
+ u.putFloat(null, addr + 24, q02 + q13);
+ u.putFloat(null, addr + 28, q12 - q03);
+ u.putFloat(null, addr + 32, 1.0f - q11 - q00);
+ }
+
+ public static void putMatrix4f(Quaternionf q, long addr) {
+ float dx = q.x + q.x;
+ float dy = q.y + q.y;
+ float dz = q.z + q.z;
+ float q00 = dx * q.x;
+ float q11 = dy * q.y;
+ float q22 = dz * q.z;
+ float q01 = dx * q.y;
+ float q02 = dx * q.z;
+ float q03 = dx * q.w;
+ float q12 = dy * q.z;
+ float q13 = dy * q.w;
+ float q23 = dz * q.w;
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, addr, 1.0f - q11 - q22);
+ u.putFloat(null, addr + 4, q01 + q23);
+ u.putLong(null, addr + 8, Float.floatToRawIntBits(q02 - q13) & 0xFFFFFFFFL);
+ u.putFloat(null, addr + 16, q01 - q23);
+ u.putFloat(null, addr + 20, 1.0f - q22 - q00);
+ u.putLong(null, addr + 24, Float.floatToRawIntBits(q12 + q03) & 0xFFFFFFFFL);
+ u.putFloat(null, addr + 32, q02 + q13);
+ u.putFloat(null, addr + 36, q12 - q03);
+ u.putLong(null, addr + 40, Float.floatToRawIntBits(1.0f - q11 - q00) & 0xFFFFFFFFL);
+ u.putLong(null, addr + 48, 0L);
+ u.putLong(null, addr + 56, 0x3F80000000000000L);
+ }
+
+ public static void putMatrix4x3f(Quaternionf q, long addr) {
+ float dx = q.x + q.x;
+ float dy = q.y + q.y;
+ float dz = q.z + q.z;
+ float q00 = dx * q.x;
+ float q11 = dy * q.y;
+ float q22 = dz * q.z;
+ float q01 = dx * q.y;
+ float q02 = dx * q.z;
+ float q03 = dx * q.w;
+ float q12 = dy * q.z;
+ float q13 = dy * q.w;
+ float q23 = dz * q.w;
+ sun.misc.Unsafe u = UNSAFE;
+ u.putFloat(null, addr, 1.0f - q11 - q22);
+ u.putFloat(null, addr + 4, q01 + q23);
+ u.putFloat(null, addr + 8, q02 - q13);
+ u.putFloat(null, addr + 12, q01 - q23);
+ u.putFloat(null, addr + 16, 1.0f - q22 - q00);
+ u.putFloat(null, addr + 20, q12 + q03);
+ u.putFloat(null, addr + 24, q02 + q13);
+ u.putFloat(null, addr + 28, q12 - q03);
+ u.putFloat(null, addr + 32, 1.0f - q11 - q00);
+ u.putLong(null, addr + 36, 0L);
+ u.putFloat(null, addr + 44, 0.0f);
+ }
+
+ private static void throwNoDirectBufferException() {
+ throw new IllegalArgumentException("Must use a direct buffer");
+ }
+
+ public void putMatrix3f(Quaternionf q, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 2);
+ putMatrix3f(q, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putMatrix3f(Quaternionf q, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ putMatrix3f(q, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ private static void checkPut(int offset, boolean direct, int capacity, int i) {
+ if (!direct)
+ throwNoDirectBufferException();
+ if (capacity - offset < i)
+ throw new BufferOverflowException();
+ }
+
+ public void putMatrix4f(Quaternionf q, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ putMatrix4f(q, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putMatrix4f(Quaternionf q, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ putMatrix4f(q, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putMatrix4x3f(Quaternionf q, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ putMatrix4x3f(q, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putMatrix4x3f(Quaternionf q, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ putMatrix4x3f(q, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Matrix4f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Matrix4f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x3(Matrix4f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put4x3(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put4x3(Matrix4f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ put4x3(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put3x4(Matrix4f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put3x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put3x4(Matrix4f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ put3x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix4x3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Matrix4x3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x4(Matrix4x3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put4x4(Matrix4x3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put3x4(Matrix4x3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put3x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put3x4(Matrix4x3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ put3x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x4(Matrix4x3d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put4x4(Matrix4x3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 3);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x4(Matrix3x2f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put4x4(Matrix3x2f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x4(Matrix3x2d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put4x4(Matrix3x2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 3);
+ put4x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put3x3(Matrix3x2f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ put3x3(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put3x3(Matrix3x2f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 2);
+ put3x3(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put3x3(Matrix3x2d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ put3x3(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put3x3(Matrix3x2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 3);
+ put3x3(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix4f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putTransposed(Matrix4f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x3Transposed(Matrix4f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put4x3Transposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put4x3Transposed(Matrix4f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ put4x3Transposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix4x3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putTransposed(Matrix4x3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putTransposed(Matrix3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 2);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix2f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putTransposed(Matrix2f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix4d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Matrix4d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 3);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix4x3d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Matrix4x3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 3);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putf(Matrix4d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putf(Matrix4d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putf(Matrix4x3d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putf(Matrix4x3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix4d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void putTransposed(Matrix4d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 3);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put4x3Transposed(Matrix4d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put4x3Transposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put4x3Transposed(Matrix4d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 3);
+ put4x3Transposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix4x3d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void putTransposed(Matrix4x3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 3);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putTransposed(Matrix2d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void putTransposed(Matrix2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 3);
+ putTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putfTransposed(Matrix4d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16);
+ putfTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putfTransposed(Matrix4d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 16 << 2);
+ putfTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putfTransposed(Matrix4x3d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ putfTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putfTransposed(Matrix4x3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ putfTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putfTransposed(Matrix2d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ putfTransposed(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putfTransposed(Matrix2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ putfTransposed(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Matrix3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 2);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put3x4(Matrix3f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12);
+ put3x4(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put3x4(Matrix3f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 12 << 2);
+ put3x4(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix3d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Matrix3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 3);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix3x2f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 6);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Matrix3x2f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 6 << 2);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix3x2d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 6);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Matrix3x2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 6 << 3);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putf(Matrix3d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putf(Matrix3d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 9 << 2);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix2f m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Matrix2f m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Matrix2d m, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Matrix2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2 << 3);
+ put(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putf(Matrix2d m, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void putf(Matrix2d m, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ putf(m, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector4d src, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Vector4d src, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ putf(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector4d src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 3);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putf(Vector4d src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ putf(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector4f src, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector4f src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector4i src, int offset, IntBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector4i src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 4 << 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector3f src, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector3f src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3 << 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector3d src, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Vector3d src, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3);
+ putf(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector3d src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3 << 3);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void putf(Vector3d src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3 << 2);
+ putf(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector3i src, int offset, IntBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector3i src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 3 << 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector2f src, int offset, FloatBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector2f src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2 << 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector2d src, int offset, DoubleBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 3));
+ }
+
+ public void put(Vector2d src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2 << 3);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void put(Vector2i src, int offset, IntBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + (offset << 2));
+ }
+
+ public void put(Vector2i src, int offset, ByteBuffer dest) {
+ if (Options.DEBUG) checkPut(offset, dest.isDirect(), dest.capacity(), 2 << 2);
+ put(src, UNSAFE.getLong(dest, ADDRESS) + offset);
+ }
+
+ public void get(Matrix4f m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 16);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Matrix4f m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 16 << 2);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public float get(Matrix4f m, int column, int row) {
+ return UNSAFE.getFloat(m, Matrix4f_m00 + (column << 4) + (row << 2));
+ }
+
+ public Matrix4f set(Matrix4f m, int column, int row, float value) {
+ UNSAFE.putFloat(m, Matrix4f_m00 + (column << 4) + (row << 2), value);
+ return m;
+ }
+
+ public double get(Matrix4d m, int column, int row) {
+ return UNSAFE.getDouble(m, Matrix4d_m00 + (column << 5) + (row << 3));
+ }
+
+ public Matrix4d set(Matrix4d m, int column, int row, double value) {
+ UNSAFE.putDouble(m, Matrix4d_m00 + (column << 5) + (row << 3), value);
+ return m;
+ }
+
+ public float get(Matrix3f m, int column, int row) {
+ return UNSAFE.getFloat(m, Matrix3f_m00 + (column * (3<<2)) + (row << 2));
+ }
+
+ public Matrix3f set(Matrix3f m, int column, int row, float value) {
+ UNSAFE.putFloat(m, Matrix3f_m00 + (column * (3<<2)) + (row << 2), value);
+ return m;
+ }
+
+ public double get(Matrix3d m, int column, int row) {
+ return UNSAFE.getDouble(m, Matrix3d_m00 + (column * (3<<3)) + (row << 3));
+ }
+
+ public Matrix3d set(Matrix3d m, int column, int row, double value) {
+ UNSAFE.putDouble(m, Matrix3d_m00 + (column * (3<<3)) + (row << 3), value);
+ return m;
+ }
+
+ public void get(Matrix4x3f m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 12);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Matrix4x3f m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 12 << 2);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix4d m, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 16);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Matrix4d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 16 << 3);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix4x3d m, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 12);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Matrix4x3d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 12 << 3);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void getf(Matrix4d m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 16);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void getf(Matrix4d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 16 << 2);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void getf(Matrix4x3d m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 12);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ private static void checkGet(int offset, boolean direct, int capacity, int i) {
+ if (!direct)
+ throwNoDirectBufferException();
+ if (capacity - offset < i)
+ throw new BufferUnderflowException();
+ }
+
+ public void getf(Matrix4x3d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 12 << 2);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix3f m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 9);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Matrix3f m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 9 << 2);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix3d m, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 9);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Matrix3d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 9 << 3);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix3x2f m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 6);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Matrix3x2f m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 6 << 2);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix3x2d m, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 6);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Matrix3x2d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 6 << 3);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void getf(Matrix3d m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 9);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void getf(Matrix3d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 9 << 2);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix2f m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Matrix2f m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4 << 2);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Matrix2d m, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4);
+ get(m, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Matrix2d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4 << 3);
+ get(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void getf(Matrix2d m, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void getf(Matrix2d m, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4 << 2);
+ getf(m, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector4d dst, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Vector4d dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4 << 3);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector4f dst, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Vector4f dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4 << 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector4i dst, int offset, IntBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Vector4i dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 4 << 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector3f dst, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 3);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Vector3f dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 3 << 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector3d dst, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 3);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Vector3d dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 3 << 3);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector3i dst, int offset, IntBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 3);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Vector3i dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 3 << 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector2f dst, int offset, FloatBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Vector2f dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 2 << 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector2d dst, int offset, DoubleBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 3));
+ }
+
+ public void get(Vector2d dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 2 << 3);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+
+ public void get(Vector2i dst, int offset, IntBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + (offset << 2));
+ }
+
+ public void get(Vector2i dst, int offset, ByteBuffer src) {
+ if (Options.DEBUG) checkGet(offset, src.isDirect(), src.capacity(), 2 << 2);
+ get(dst, UNSAFE.getLong(src, ADDRESS) + offset);
+ }
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Options.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Options.java
new file mode 100644
index 000000000..efee2e259
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Options.java
@@ -0,0 +1,116 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Utility class for reading system properties.
+ *
+ * @author Kai Burjack
+ */
+public final class Options {
+
+ /**
+ * Whether certain debugging checks should be made, such as that only direct NIO Buffers are used when Unsafe is active,
+ * and a proxy should be created on calls to readOnlyView().
+ */
+ public static final boolean DEBUG = hasOption(System.getProperty("joml.debug", "false"));
+
+ /**
+ * Whether not to use sun.misc.Unsafe when copying memory with MemUtil.
+ */
+ public static final boolean NO_UNSAFE = hasOption(System.getProperty("joml.nounsafe", "false"));
+ /**
+ * Whether to force the use of sun.misc.Unsafe when copying memory with MemUtil.
+ */
+ public static final boolean FORCE_UNSAFE = hasOption(System.getProperty("joml.forceUnsafe", "false"));
+
+ /**
+ * Whether fast approximations of some java.lang.Math operations should be used.
+ */
+ public static final boolean FASTMATH = hasOption(System.getProperty("joml.fastmath", "false"));
+
+ /**
+ * When {@link #FASTMATH} is true
, whether to use a lookup table for sin/cos.
+ */
+ public static final boolean SIN_LOOKUP = hasOption(System.getProperty("joml.sinLookup", "false"));
+
+ /**
+ * When {@link #SIN_LOOKUP} is true
, this determines the table size.
+ */
+ public static final int SIN_LOOKUP_BITS = Integer.parseInt(System.getProperty("joml.sinLookup.bits", "14"));
+
+ /**
+ * Whether to use a {@link NumberFormat} producing scientific notation output when formatting matrix,
+ * vector and quaternion components to strings.
+ */
+ public static final boolean useNumberFormat = hasOption(System.getProperty("joml.format", "true"));
+
+ /**
+ * Whether to try using java.lang.Math.fma() in most matrix/vector/quaternion operations if it is available.
+ * If the CPU does not support it, it will be a lot slower than `a*b+c` and potentially generate a lot of memory allocations
+ * for the emulation with `java.util.BigDecimal`, though.
+ */
+ public static final boolean USE_MATH_FMA = hasOption(System.getProperty("joml.useMathFma", "false"));
+
+ /**
+ * When {@link #useNumberFormat} is true
then this determines the number of decimal digits
+ * produced in the formatted numbers.
+ */
+ public static final int numberFormatDecimals = Integer.parseInt(System.getProperty("joml.format.decimals", "3"));
+
+ /**
+ * The {@link NumberFormat} used to format all numbers throughout all JOML classes.
+ */
+ public static final NumberFormat NUMBER_FORMAT = decimalFormat();
+
+ private Options() {
+ }
+
+ private static NumberFormat decimalFormat() {
+ NumberFormat df;
+ if (useNumberFormat) {
+ char[] prec = new char[numberFormatDecimals];
+ Arrays.fill(prec, '0');
+ df = new DecimalFormat(" 0." + new String(prec) + "E0;-");
+ } else {
+ df = NumberFormat.getNumberInstance(Locale.ENGLISH);
+ df.setGroupingUsed(false);
+ }
+ return df;
+ }
+
+ private static boolean hasOption(String v) {
+ if (v == null)
+ return false;
+ if (v.trim().length() == 0)
+ return true;
+ return Boolean.valueOf(v).booleanValue();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/PolygonsIntersection.java b/src/main/java/com/jozufozu/flywheel/repack/joml/PolygonsIntersection.java
new file mode 100644
index 000000000..c44f23e35
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/PolygonsIntersection.java
@@ -0,0 +1,328 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Class for polygon/point intersection tests when testing many points against one or many static concave or convex, simple polygons.
+ *
+ * This is an implementation of the algorithm described in http://alienryderflex.com and augmented with using a
+ * custom interval tree to avoid testing all polygon edges against a point, but only those that intersect the imaginary ray along the same y co-ordinate of the
+ * search point. This algorithm additionally also supports multiple polygons.
+ *
+ * This class is thread-safe and can be used in a multithreaded environment when testing many points against the same polygon concurrently.
+ *
+ * Reference: http://alienryderflex.com
+ *
+ * @author Kai Burjack
+ */
+public class PolygonsIntersection {
+
+ static class ByStartComparator implements Comparator {
+ public int compare(Object o1, Object o2) {
+ Interval i1 = (Interval) o1;
+ Interval i2 = (Interval) o2;
+ return Float.compare(i1.start, i2.start);
+ }
+ }
+
+ static class ByEndComparator implements Comparator {
+ public int compare(Object o1, Object o2) {
+ Interval i1 = (Interval) o1;
+ Interval i2 = (Interval) o2;
+ return Float.compare(i2.end, i1.end);
+ }
+ }
+
+ static class Interval {
+ float start, end;
+ int i, j, polyIndex;
+ }
+
+ static class IntervalTreeNode {
+ float center;
+ float childrenMinMax;
+ IntervalTreeNode left;
+ IntervalTreeNode right;
+ List/* */ byBeginning;
+ List/* */ byEnding;
+
+ static boolean computeEvenOdd(float[] verticesXY, Interval ival, float x, float y, boolean evenOdd, BitSet inPolys) {
+ boolean newEvenOdd = evenOdd;
+ int i = ival.i;
+ int j = ival.j;
+ float yi = verticesXY[2 * i + 1];
+ float yj = verticesXY[2 * j + 1];
+ float xi = verticesXY[2 * i + 0];
+ float xj = verticesXY[2 * j + 0];
+ if ((yi < y && yj >= y || yj < y && yi >= y) && (xi <= x || xj <= x)) {
+ float xDist = xi + (y - yi) / (yj - yi) * (xj - xi) - x;
+ newEvenOdd ^= xDist < 0.0f;
+ if (newEvenOdd != evenOdd && inPolys != null) {
+ inPolys.flip(ival.polyIndex);
+ }
+ }
+ return newEvenOdd;
+ }
+
+ boolean traverse(float[] verticesXY, float x, float y, boolean evenOdd, BitSet inPolys) {
+ boolean newEvenOdd = evenOdd;
+ if (y == center && byBeginning != null) {
+ int size = byBeginning.size();
+ for (int b = 0; b < size; b++) {
+ Interval ival = (Interval) byBeginning.get(b);
+ newEvenOdd = computeEvenOdd(verticesXY, ival, x, y, newEvenOdd, inPolys);
+ }
+ } else if (y < center) {
+ if (left != null && left.childrenMinMax >= y)
+ newEvenOdd = left.traverse(verticesXY, x, y, newEvenOdd, inPolys);
+ if (byBeginning != null) {
+ int size = byBeginning.size();
+ for (int b = 0; b < size; b++) {
+ Interval ival = (Interval) byBeginning.get(b);
+ if (ival.start > y)
+ break;
+ newEvenOdd = computeEvenOdd(verticesXY, ival, x, y, newEvenOdd, inPolys);
+ }
+ }
+ } else if (y > center) {
+ if (right != null && right.childrenMinMax <= y)
+ newEvenOdd = right.traverse(verticesXY, x, y, newEvenOdd, inPolys);
+ if (byEnding != null) {
+ int size = byEnding.size();
+ for (int b = 0; b < size; b++) {
+ Interval ival = (Interval) byEnding.get(b);
+ if (ival.end < y)
+ break;
+ newEvenOdd = computeEvenOdd(verticesXY, ival, x, y, newEvenOdd, inPolys);
+ }
+ }
+ }
+ return newEvenOdd;
+ }
+ }
+
+ private static final ByStartComparator byStartComparator = new ByStartComparator();
+ private static final ByEndComparator byEndComparator = new ByEndComparator();
+
+ protected final float[] verticesXY;
+ private float minX, minY, maxX, maxY;
+ private float centerX, centerY, radiusSquared;
+ private IntervalTreeNode tree;
+
+ /**
+ * Create a new {@link PolygonsIntersection} object with the given polygon vertices.
+ *
+ * The verticesXY
array contains the x and y coordinates of all vertices. This array will not be copied so its content must remain constant for
+ * as long as the PolygonPointIntersection is used with it.
+ *
+ * @param verticesXY
+ * contains the x and y coordinates of all vertices
+ * @param polygons
+ * defines the start vertices of a new polygon. The first vertex of the first polygon is always the
+ * vertex with index 0. In order to define a hole simply define a polygon that is completely inside another polygon
+ * @param count
+ * the number of vertices to use from the verticesXY
array, staring with index 0
+ */
+ public PolygonsIntersection(float[] verticesXY, int[] polygons, int count) {
+ this.verticesXY = verticesXY;
+ // Do all the allocations and initializations during this constructor
+ preprocess(count, polygons);
+ }
+
+ private IntervalTreeNode buildNode(List intervals, float center) {
+ List left = null;
+ List right = null;
+ List byStart = null;
+ List byEnd = null;
+ float leftMin = 1E38f, leftMax = -1E38f, rightMin = 1E38f, rightMax = -1E38f;
+ float thisMin = 1E38f, thisMax = -1E38f;
+ for (int i = 0; i < intervals.size(); i++) {
+ Interval ival = (Interval) intervals.get(i);
+ if (ival.start < center && ival.end < center) {
+ if (left == null)
+ left = new ArrayList();
+ left.add(ival);
+ leftMin = leftMin < ival.start ? leftMin : ival.start;
+ leftMax = leftMax > ival.end ? leftMax : ival.end;
+ } else if (ival.start > center && ival.end > center) {
+ if (right == null)
+ right = new ArrayList();
+ right.add(ival);
+ rightMin = rightMin < ival.start ? rightMin : ival.start;
+ rightMax = rightMax > ival.end ? rightMax : ival.end;
+ } else {
+ if (byStart == null || byEnd == null) {
+ byStart = new ArrayList();
+ byEnd = new ArrayList();
+ }
+ thisMin = ival.start < thisMin ? ival.start : thisMin;
+ thisMax = ival.end > thisMax ? ival.end : thisMax;
+ byStart.add(ival);
+ byEnd.add(ival);
+ }
+ }
+ if (byStart != null) {
+ Collections.sort(byStart, byStartComparator);
+ Collections.sort(byEnd, byEndComparator);
+ }
+ IntervalTreeNode tree = new IntervalTreeNode();
+ tree.byBeginning = byStart;
+ tree.byEnding = byEnd;
+ tree.center = center;
+ if (left != null) {
+ tree.left = buildNode(left, (leftMin + leftMax) / 2.0f);
+ tree.left.childrenMinMax = leftMax;
+ }
+ if (right != null) {
+ tree.right = buildNode(right, (rightMin + rightMax) / 2.0f);
+ tree.right.childrenMinMax = rightMin;
+ }
+ return tree;
+ }
+
+ private void preprocess(int count, int[] polygons) {
+ int i, j = 0;
+ minX = minY = 1E38f;
+ maxX = maxY = -1E38f;
+ List intervals = new ArrayList(count);
+ int first = 0;
+ int currPoly = 0;
+ for (i = 1; i < count; i++) {
+ if (polygons != null && polygons.length > currPoly && polygons[currPoly] == i) {
+ /* New polygon starts. End the current. */
+ float prevy = verticesXY[2 * (i - 1) + 1];
+ float firsty = verticesXY[2 * first + 1];
+ Interval ival = new Interval();
+ ival.start = prevy < firsty ? prevy : firsty;
+ ival.end = firsty > prevy ? firsty : prevy;
+ ival.i = i - 1;
+ ival.j = first;
+ ival.polyIndex = currPoly;
+ intervals.add(ival);
+ first = i;
+ currPoly++;
+ i++;
+ j = i - 1;
+ }
+ float yi = verticesXY[2 * i + 1];
+ float xi = verticesXY[2 * i + 0];
+ float yj = verticesXY[2 * j + 1];
+ minX = xi < minX ? xi : minX;
+ minY = yi < minY ? yi : minY;
+ maxX = xi > maxX ? xi : maxX;
+ maxY = yi > maxY ? yi : maxY;
+ Interval ival = new Interval();
+ ival.start = yi < yj ? yi : yj;
+ ival.end = yj > yi ? yj : yi;
+ ival.i = i;
+ ival.j = j;
+ ival.polyIndex = currPoly;
+ intervals.add(ival);
+ j = i;
+ }
+ // Close current polygon
+ float yi = verticesXY[2 * (i - 1) + 1];
+ float xi = verticesXY[2 * (i - 1) + 0];
+ float yj = verticesXY[2 * first + 1];
+ minX = xi < minX ? xi : minX;
+ minY = yi < minY ? yi : minY;
+ maxX = xi > maxX ? xi : maxX;
+ maxY = yi > maxY ? yi : maxY;
+ Interval ival = new Interval();
+ ival.start = yi < yj ? yi : yj;
+ ival.end = yj > yi ? yj : yi;
+ ival.i = i - 1;
+ ival.j = first;
+ ival.polyIndex = currPoly;
+ intervals.add(ival);
+ // compute bounding sphere and rectangle
+ centerX = (maxX + minX) * 0.5f;
+ centerY = (maxY + minY) * 0.5f;
+ float dx = maxX - centerX;
+ float dy = maxY - centerY;
+ radiusSquared = dx * dx + dy * dy;
+ // build interval tree
+ tree = buildNode(intervals, centerY);
+ }
+
+ /**
+ * Test whether the given point (x, y)
lies inside any polygon stored in this {@link PolygonsIntersection} object.
+ *
+ * This method is thread-safe and can be used to test many points concurrently.
+ *
+ * In order to obtain the index of the polygon the point is inside of, use {@link #testPoint(float, float, BitSet)}
+ *
+ * @see #testPoint(float, float, BitSet)
+ *
+ * @param x
+ * the x coordinate of the point to test
+ * @param y
+ * the y coordinate of the point to test
+ * @return true
iff the point lies inside any polygon; false
otherwise
+ */
+ public boolean testPoint(float x, float y) {
+ return testPoint(x, y, null);
+ }
+
+ /**
+ * Test whether the given point (x, y)
lies inside any polygon stored in this {@link PolygonsIntersection} object.
+ *
+ * This method is thread-safe and can be used to test many points concurrently.
+ *
+ * @param x
+ * the x coordinate of the point to test
+ * @param y
+ * the y coordinate of the point to test
+ * @param inPolys
+ * if not null
then the i-th bit is set if the given point is inside the i-th polygon
+ * @return true
iff the point lies inside the polygon and not inside a hole; false
otherwise
+ */
+ public boolean testPoint(float x, float y, BitSet inPolys) {
+ // check bounding sphere first
+ float dx = (x - centerX);
+ float dy = (y - centerY);
+ if (inPolys != null)
+ inPolys.clear();
+ if (dx * dx + dy * dy > radiusSquared)
+ return false;
+ // check bounding box next
+ if (maxX < x || maxY < y || minX > x || minY > y)
+ return false;
+ // ask interval tree for all polygon edges intersecting 'y' and perform
+ // the even/odd/crosscutting/raycast algorithm on them and also return
+ // the polygon index of the polygon the point is in by setting the appropriate
+ // bit in the given BitSet.
+ boolean res = tree.traverse(verticesXY, x, y, false, inPolys);
+ return res;
+ }
+
+}
+
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Quaterniond.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaterniond.java
new file mode 100644
index 000000000..7b4a33e29
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaterniond.java
@@ -0,0 +1,2985 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Quaternion of 4 double-precision floats which can represent rotation and uniform scaling.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Quaterniond implements Externalizable, Cloneable, Quaterniondc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The first component of the vector part.
+ */
+ public double x;
+ /**
+ * The second component of the vector part.
+ */
+ public double y;
+ /**
+ * The third component of the vector part.
+ */
+ public double z;
+ /**
+ * The real/scalar part of the quaternion.
+ */
+ public double w;
+
+ /**
+ * Create a new {@link Quaterniond} and initialize it with (x=0, y=0, z=0, w=1)
,
+ * where (x, y, z)
is the vector part of the quaternion and w
is the real/scalar part.
+ */
+ public Quaterniond() {
+ this.w = 1.0;
+ }
+
+ /**
+ * Create a new {@link Quaterniond} and initialize its components to the given values.
+ *
+ * @param x
+ * the first component of the imaginary part
+ * @param y
+ * the second component of the imaginary part
+ * @param z
+ * the third component of the imaginary part
+ * @param w
+ * the real part
+ */
+ public Quaterniond(double x, double y, double z, double w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Quaterniond} and initialize its components to the same values as the given {@link Quaterniondc}.
+ *
+ * @param source
+ * the {@link Quaterniondc} to take the component values from
+ */
+ public Quaterniond(Quaterniondc source) {
+ x = source.x();
+ y = source.y();
+ z = source.z();
+ w = source.w();
+ }
+
+ /**
+ * Create a new {@link Quaterniond} and initialize its components to the same values as the given {@link Quaternionfc}.
+ *
+ * @param source
+ * the {@link Quaternionfc} to take the component values from
+ */
+ public Quaterniond(Quaternionfc source) {
+ x = source.x();
+ y = source.y();
+ z = source.z();
+ w = source.w();
+ }
+
+ /**
+ * Create a new {@link Quaterniond} and initialize it to represent the same rotation as the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the axis-angle to initialize this quaternion with
+ */
+ public Quaterniond(AxisAngle4f axisAngle) {
+ double s = Math.sin(axisAngle.angle * 0.5);
+ x = axisAngle.x * s;
+ y = axisAngle.y * s;
+ z = axisAngle.z * s;
+ w = Math.cosFromSin(s, axisAngle.angle * 0.5);
+ }
+
+ /**
+ * Create a new {@link Quaterniond} and initialize it to represent the same rotation as the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the axis-angle to initialize this quaternion with
+ */
+ public Quaterniond(AxisAngle4d axisAngle) {
+ double s = Math.sin(axisAngle.angle * 0.5);
+ x = axisAngle.x * s;
+ y = axisAngle.y * s;
+ z = axisAngle.z * s;
+ w = Math.cosFromSin(s, axisAngle.angle * 0.5);
+ }
+
+ /**
+ * @return the first component of the vector part
+ */
+ public double x() {
+ return this.x;
+ }
+
+ /**
+ * @return the second component of the vector part
+ */
+ public double y() {
+ return this.y;
+ }
+
+ /**
+ * @return the third component of the vector part
+ */
+ public double z() {
+ return this.z;
+ }
+
+ /**
+ * @return the real/scalar part of the quaternion
+ */
+ public double w() {
+ return this.w;
+ }
+
+ /**
+ * Normalize this quaternion.
+ *
+ * @return this
+ */
+ public Quaterniond normalize() {
+ double invNorm = Math.invsqrt(lengthSquared());
+ x *= invNorm;
+ y *= invNorm;
+ z *= invNorm;
+ w *= invNorm;
+ return this;
+ }
+
+ public Quaterniond normalize(Quaterniond dest) {
+ double invNorm = Math.invsqrt(lengthSquared());
+ dest.x = x * invNorm;
+ dest.y = y * invNorm;
+ dest.z = z * invNorm;
+ dest.w = w * invNorm;
+ return dest;
+ }
+
+ /**
+ * Add the quaternion (x, y, z, w)
to this quaternion.
+ *
+ * @param x
+ * the x component of the vector part
+ * @param y
+ * the y component of the vector part
+ * @param z
+ * the z component of the vector part
+ * @param w
+ * the real/scalar component
+ * @return this
+ */
+ public Quaterniond add(double x, double y, double z, double w) {
+ return add(x, y, z, w, this);
+ }
+
+ public Quaterniond add(double x, double y, double z, double w, Quaterniond dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ dest.w = this.w + w;
+ return dest;
+ }
+
+ /**
+ * Add q2
to this quaternion.
+ *
+ * @param q2
+ * the quaternion to add to this
+ * @return this
+ */
+ public Quaterniond add(Quaterniondc q2) {
+ x += q2.x();
+ y += q2.y();
+ z += q2.z();
+ w += q2.w();
+ return this;
+ }
+
+ public Quaterniond add(Quaterniondc q2, Quaterniond dest) {
+ dest.x = x + q2.x();
+ dest.y = y + q2.y();
+ dest.z = z + q2.z();
+ dest.w = w + q2.w();
+ return dest;
+ }
+
+ public double dot(Quaterniondc otherQuat) {
+ return this.x * otherQuat.x() + this.y * otherQuat.y() + this.z * otherQuat.z() + this.w * otherQuat.w();
+ }
+
+ public double angle() {
+ return 2.0 * Math.safeAcos(w);
+ }
+
+ public Matrix3d get(Matrix3d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3f get(Matrix3f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4d get(Matrix4d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4f get(Matrix4f dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4f get(AxisAngle4f dest) {
+ double x = this.x;
+ double y = this.y;
+ double z = this.z;
+ double w = this.w;
+ if (w > 1.0) {
+ double invNorm = Math.invsqrt(lengthSquared());
+ x *= invNorm;
+ y *= invNorm;
+ z *= invNorm;
+ w *= invNorm;
+ }
+ dest.angle = (float) (2.0 * Math.acos(w));
+ double s = Math.sqrt(1.0 - w * w);
+ if (s < 0.001) {
+ dest.x = (float) x;
+ dest.y = (float) y;
+ dest.z = (float) z;
+ } else {
+ s = 1.0 / s;
+ dest.x = (float) (x * s);
+ dest.y = (float) (y * s);
+ dest.z = (float) (z * s);
+ }
+ return dest;
+ }
+
+ public AxisAngle4d get(AxisAngle4d dest) {
+ double x = this.x;
+ double y = this.y;
+ double z = this.z;
+ double w = this.w;
+ if (w > 1.0) {
+ double invNorm = Math.invsqrt(lengthSquared());
+ x *= invNorm;
+ y *= invNorm;
+ z *= invNorm;
+ w *= invNorm;
+ }
+ dest.angle = 2.0 * Math.acos(w);
+ double s = Math.sqrt(1.0 - w * w);
+ if (s < 0.001) {
+ dest.x = x;
+ dest.y = y;
+ dest.z = z;
+ } else {
+ s = 1.0 / s;
+ dest.x = x * s;
+ dest.y = y * s;
+ dest.z = z * s;
+ }
+ return dest;
+ }
+
+ /**
+ * Set the given {@link Quaterniond} to the values of this
.
+ *
+ * @see #set(Quaterniondc)
+ *
+ * @param dest
+ * the {@link Quaterniond} to set
+ * @return the passed in destination
+ */
+ public Quaterniond get(Quaterniond dest) {
+ return dest.set(this);
+ }
+
+ /**
+ * Set the given {@link Quaternionf} to the values of this
.
+ *
+ * @see #set(Quaterniondc)
+ *
+ * @param dest
+ * the {@link Quaternionf} to set
+ * @return the passed in destination
+ */
+ public Quaternionf get(Quaternionf dest) {
+ return dest.set(this);
+ }
+
+ /**
+ * Set this quaternion to the new values.
+ *
+ * @param x
+ * the new value of x
+ * @param y
+ * the new value of y
+ * @param z
+ * the new value of z
+ * @param w
+ * the new value of w
+ * @return this
+ */
+ public Quaterniond set(double x, double y, double z, double w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a copy of q.
+ *
+ * @param q
+ * the {@link Quaterniondc} to copy
+ * @return this
+ */
+ public Quaterniond set(Quaterniondc q) {
+ x = q.x();
+ y = q.y();
+ z = q.z();
+ w = q.w();
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a copy of q.
+ *
+ * @param q
+ * the {@link Quaternionfc} to copy
+ * @return this
+ */
+ public Quaterniond set(Quaternionfc q) {
+ x = q.x();
+ y = q.y();
+ z = q.z();
+ w = q.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Quaterniond} to be equivalent to the given
+ * {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Quaterniond set(AxisAngle4f axisAngle) {
+ return setAngleAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this {@link Quaterniond} to be equivalent to the given
+ * {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Quaterniond set(AxisAngle4d axisAngle) {
+ return setAngleAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this quaternion to a rotation equivalent to the supplied axis and
+ * angle (in radians).
+ *
+ * This method assumes that the given rotation axis (x, y, z)
is already normalized
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the normalized rotation axis
+ * @param y
+ * the y-component of the normalized rotation axis
+ * @param z
+ * the z-component of the normalized rotation axis
+ * @return this
+ */
+ public Quaterniond setAngleAxis(double angle, double x, double y, double z) {
+ double s = Math.sin(angle * 0.5);
+ this.x = x * s;
+ this.y = y * s;
+ this.z = z * s;
+ this.w = Math.cosFromSin(s, angle * 0.5);
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in radians).
+ *
+ * @param angle
+ * the angle in radians
+ * @param axis
+ * the rotation axis
+ * @return this
+ */
+ public Quaterniond setAngleAxis(double angle, Vector3dc axis) {
+ return setAngleAxis(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ private void setFromUnnormalized(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) {
+ double nm00 = m00, nm01 = m01, nm02 = m02;
+ double nm10 = m10, nm11 = m11, nm12 = m12;
+ double nm20 = m20, nm21 = m21, nm22 = m22;
+ double lenX = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ double lenY = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ double lenZ = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ nm00 *= lenX; nm01 *= lenX; nm02 *= lenX;
+ nm10 *= lenY; nm11 *= lenY; nm12 *= lenY;
+ nm20 *= lenZ; nm21 *= lenZ; nm22 *= lenZ;
+ setFromNormalized(nm00, nm01, nm02, nm10, nm11, nm12, nm20, nm21, nm22);
+ }
+
+ private void setFromNormalized(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) {
+ double t;
+ double tr = m00 + m11 + m22;
+ if (tr >= 0.0) {
+ t = Math.sqrt(tr + 1.0);
+ w = t * 0.5;
+ t = 0.5 / t;
+ x = (m12 - m21) * t;
+ y = (m20 - m02) * t;
+ z = (m01 - m10) * t;
+ } else {
+ if (m00 >= m11 && m00 >= m22) {
+ t = Math.sqrt(m00 - (m11 + m22) + 1.0);
+ x = t * 0.5;
+ t = 0.5 / t;
+ y = (m10 + m01) * t;
+ z = (m02 + m20) * t;
+ w = (m12 - m21) * t;
+ } else if (m11 > m22) {
+ t = Math.sqrt(m11 - (m22 + m00) + 1.0);
+ y = t * 0.5;
+ t = 0.5 / t;
+ z = (m21 + m12) * t;
+ x = (m10 + m01) * t;
+ w = (m20 - m02) * t;
+ } else {
+ t = Math.sqrt(m22 - (m00 + m11) + 1.0);
+ z = t * 0.5;
+ t = 0.5 / t;
+ x = (m02 + m20) * t;
+ y = (m21 + m12) * t;
+ w = (m01 - m10) * t;
+ }
+ }
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromUnnormalized(Matrix4fc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromUnnormalized(Matrix4x3fc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromUnnormalized(Matrix4x3dc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromNormalized(Matrix4fc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromNormalized(Matrix4x3fc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromNormalized(Matrix4x3dc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromUnnormalized(Matrix4dc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromNormalized(Matrix4dc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromUnnormalized(Matrix3fc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromNormalized(Matrix3fc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromUnnormalized(Matrix3dc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaterniond setFromNormalized(Matrix3dc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in radians).
+ *
+ * @param axis
+ * the rotation axis
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Quaterniond fromAxisAngleRad(Vector3dc axis, double angle) {
+ return fromAxisAngleRad(axis.x(), axis.y(), axis.z(), angle);
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in radians).
+ *
+ * @param axisX
+ * the x component of the rotation axis
+ * @param axisY
+ * the y component of the rotation axis
+ * @param axisZ
+ * the z component of the rotation axis
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Quaterniond fromAxisAngleRad(double axisX, double axisY, double axisZ, double angle) {
+ double hangle = angle / 2.0;
+ double sinAngle = Math.sin(hangle);
+ double vLength = Math.sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
+ x = axisX / vLength * sinAngle;
+ y = axisY / vLength * sinAngle;
+ z = axisZ / vLength * sinAngle;
+ w = Math.cosFromSin(sinAngle, hangle);
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in degrees).
+ *
+ * @param axis
+ * the rotation axis
+ * @param angle
+ * the angle in degrees
+ * @return this
+ */
+ public Quaterniond fromAxisAngleDeg(Vector3dc axis, double angle) {
+ return fromAxisAngleRad(axis.x(), axis.y(), axis.z(), Math.toRadians(angle));
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in degrees).
+ *
+ * @param axisX
+ * the x component of the rotation axis
+ * @param axisY
+ * the y component of the rotation axis
+ * @param axisZ
+ * the z component of the rotation axis
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Quaterniond fromAxisAngleDeg(double axisX, double axisY, double axisZ, double angle) {
+ return fromAxisAngleRad(axisX, axisY, axisZ, Math.toRadians(angle));
+ }
+
+ /**
+ * Multiply this quaternion by q
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param q
+ * the quaternion to multiply this
by
+ * @return this
+ */
+ public Quaterniond mul(Quaterniondc q) {
+ return mul(q, this);
+ }
+
+ public Quaterniond mul(Quaterniondc q, Quaterniond dest) {
+ return mul(q.x(), q.y(), q.z(), q.w(), dest);
+ }
+
+ /**
+ * Multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @return this
+ */
+ public Quaterniond mul(double qx, double qy, double qz, double qw) {
+ return mul(qx, qy, qz, qw, this);
+ }
+
+ public Quaterniond mul(double qx, double qy, double qz, double qw, Quaterniond dest) {
+ return dest.set(Math.fma(w, qx, Math.fma(x, qw, Math.fma(y, qz, -z * qy))),
+ Math.fma(w, qy, Math.fma(-x, qz, Math.fma(y, qw, z * qx))),
+ Math.fma(w, qz, Math.fma(x, qy, Math.fma(-y, qx, z * qw))),
+ Math.fma(w, qw, Math.fma(-x, qx, Math.fma(-y, qy, -z * qz))));
+ }
+
+ /**
+ * Pre-multiply this quaternion by q
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param q
+ * the quaternion to pre-multiply this
by
+ * @return this
+ */
+ public Quaterniond premul(Quaterniondc q) {
+ return premul(q, this);
+ }
+
+ public Quaterniond premul(Quaterniondc q, Quaterniond dest) {
+ return premul(q.x(), q.y(), q.z(), q.w(), dest);
+ }
+
+ /**
+ * Pre-multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @return this
+ */
+ public Quaterniond premul(double qx, double qy, double qz, double qw) {
+ return premul(qx, qy, qz, qw, this);
+ }
+
+ public Quaterniond premul(double qx, double qy, double qz, double qw, Quaterniond dest) {
+ return dest.set(Math.fma(qw, x, Math.fma(qx, w, Math.fma(qy, z, -qz * y))),
+ Math.fma(qw, y, Math.fma(-qx, z, Math.fma(qy, w, qz * x))),
+ Math.fma(qw, z, Math.fma(qx, y, Math.fma(-qy, x, qz * w))),
+ Math.fma(qw, w, Math.fma(-qx, x, Math.fma(-qy, y, -qz * z))));
+ }
+
+ public Vector3d transform(Vector3d vec){
+ return transform(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3d transformInverse(Vector3d vec){
+ return transformInverse(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3d transformUnit(Vector3d vec){
+ return transformUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3d transformInverseUnit(Vector3d vec){
+ return transformInverseUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3d transformPositiveX(Vector3d dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ dest.x = ww + xx - zz - yy;
+ dest.y = xy + zw + zw + xy;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector4d transformPositiveX(Vector4d dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ dest.x = ww + xx - zz - yy;
+ dest.y = xy + zw + zw + xy;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector3d transformUnitPositiveX(Vector3d dest) {
+ double yy = y * y;
+ double zz = z * z;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ double zw = z * w;
+ dest.x = 1.0 - yy - yy - zz - zz;
+ dest.y = xy + zw + xy + zw;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector4d transformUnitPositiveX(Vector4d dest) {
+ double yy = y * y;
+ double zz = z * z;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ double zw = z * w;
+ dest.x = 1.0 - yy - yy - zz - zz;
+ dest.y = xy + zw + xy + zw;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector3d transformPositiveY(Vector3d dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = -zw + xy - zw + xy;
+ dest.y = yy - zz + ww - xx;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector4d transformPositiveY(Vector4d dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = -zw + xy - zw + xy;
+ dest.y = yy - zz + ww - xx;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector4d transformUnitPositiveY(Vector4d dest) {
+ double xx = x * x;
+ double zz = z * z;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ double zw = z * w;
+ dest.x = xy - zw + xy - zw;
+ dest.y = 1.0 - xx - xx - zz - zz;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector3d transformUnitPositiveY(Vector3d dest) {
+ double xx = x * x;
+ double zz = z * z;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ double zw = z * w;
+ dest.x = xy - zw + xy - zw;
+ dest.y = 1.0 - xx - xx - zz - zz;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector3d transformPositiveZ(Vector3d dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double xz = x * z;
+ double yw = y * w;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = yw + xz + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = zz - yy - xx + ww;
+ return dest;
+ }
+
+ public Vector4d transformPositiveZ(Vector4d dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double xz = x * z;
+ double yw = y * w;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = yw + xz + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = zz - yy - xx + ww;
+ return dest;
+ }
+
+ public Vector4d transformUnitPositiveZ(Vector4d dest) {
+ double xx = x * x;
+ double yy = y * y;
+ double xz = x * z;
+ double yz = y * z;
+ double xw = x * w;
+ double yw = y * w;
+ dest.x = xz + yw + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = 1.0 - xx - xx - yy - yy;
+ return dest;
+ }
+
+ public Vector3d transformUnitPositiveZ(Vector3d dest) {
+ double xx = x * x;
+ double yy = y * y;
+ double xz = x * z;
+ double yz = y * z;
+ double xw = x * w;
+ double yw = y * w;
+ dest.x = xz + yw + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = 1.0 - xx - xx - yy - yy;
+ return dest;
+ }
+
+ public Vector4d transform(Vector4d vec){
+ return transform(vec, vec);
+ }
+
+ public Vector4d transformInverse(Vector4d vec){
+ return transformInverse(vec, vec);
+ }
+
+ public Vector3d transform(Vector3dc vec, Vector3d dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transformInverse(Vector3dc vec, Vector3d dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transform(double x, double y, double z, Vector3d dest) {
+ double xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ double xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ double zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3d transformInverse(double x, double y, double z, Vector3d dest) {
+ double n = 1.0 / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ double qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ double xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ double xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ double zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector4d transform(Vector4dc vec, Vector4d dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transformInverse(Vector4dc vec, Vector4d dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transform(double x, double y, double z, Vector4d dest) {
+ double xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ double xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ double zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)), dest.w);
+ }
+
+ public Vector4d transformInverse(double x, double y, double z, Vector4d dest) {
+ double n = 1.0 / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ double qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ double xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ double xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ double zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3f transform(Vector3f vec){
+ return transform(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformInverse(Vector3f vec){
+ return transformInverse(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector4d transformUnit(Vector4d vec){
+ return transformUnit(vec, vec);
+ }
+
+ public Vector4d transformInverseUnit(Vector4d vec){
+ return transformInverseUnit(vec, vec);
+ }
+
+ public Vector3d transformUnit(Vector3dc vec, Vector3d dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transformInverseUnit(Vector3dc vec, Vector3d dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transformUnit(double x, double y, double z, Vector3d dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector3d transformInverseUnit(double x, double y, double z, Vector3d dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4d transformUnit(Vector4dc vec, Vector4d dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transformInverseUnit(Vector4dc vec, Vector4d dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transformUnit(double x, double y, double z, Vector4d dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)),
+ dest.w);
+ }
+
+ public Vector4d transformInverseUnit(double x, double y, double z, Vector4d dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)),
+ dest.w);
+ }
+
+ public Vector3f transformUnit(Vector3f vec){
+ return transformUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformInverseUnit(Vector3f vec){
+ return transformInverseUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformPositiveX(Vector3f dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ dest.x = (float) (ww + xx - zz - yy);
+ dest.y = (float) (xy + zw + zw + xy);
+ dest.z = (float) (xz - yw + xz - yw);
+ return dest;
+ }
+
+ public Vector4f transformPositiveX(Vector4f dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ dest.x = (float) (ww + xx - zz - yy);
+ dest.y = (float) (xy + zw + zw + xy);
+ dest.z = (float) (xz - yw + xz - yw);
+ return dest;
+ }
+
+ public Vector3f transformUnitPositiveX(Vector3f dest) {
+ double yy = y * y;
+ double zz = z * z;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ double zw = z * w;
+ dest.x = (float) (1.0 - yy - yy - zz - zz);
+ dest.y = (float) (xy + zw + xy + zw);
+ dest.z = (float) (xz - yw + xz - yw);
+ return dest;
+ }
+
+ public Vector4f transformUnitPositiveX(Vector4f dest) {
+ double yy = y * y;
+ double zz = z * z;
+ double xy = x * y;
+ double xz = x * z;
+ double yw = y * w;
+ double zw = z * w;
+ dest.x = (float) (1.0 - yy - yy - zz - zz);
+ dest.y = (float) (xy + zw + xy + zw);
+ dest.z = (float) (xz - yw + xz - yw);
+ return dest;
+ }
+
+ public Vector3f transformPositiveY(Vector3f dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = (float) (-zw + xy - zw + xy);
+ dest.y = (float) (yy - zz + ww - xx);
+ dest.z = (float) (yz + yz + xw + xw);
+ return dest;
+ }
+
+ public Vector4f transformPositiveY(Vector4f dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double zw = z * w;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = (float) (-zw + xy - zw + xy);
+ dest.y = (float) (yy - zz + ww - xx);
+ dest.z = (float) (yz + yz + xw + xw);
+ return dest;
+ }
+
+ public Vector4f transformUnitPositiveY(Vector4f dest) {
+ double xx = x * x;
+ double zz = z * z;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ double zw = z * w;
+ dest.x = (float) (xy - zw + xy - zw);
+ dest.y = (float) (1.0 - xx - xx - zz - zz);
+ dest.z = (float) (yz + yz + xw + xw);
+ return dest;
+ }
+
+ public Vector3f transformUnitPositiveY(Vector3f dest) {
+ double xx = x * x;
+ double zz = z * z;
+ double xy = x * y;
+ double yz = y * z;
+ double xw = x * w;
+ double zw = z * w;
+ dest.x = (float) (xy - zw + xy - zw);
+ dest.y = (float) (1.0 - xx - xx - zz - zz);
+ dest.z = (float) (yz + yz + xw + xw);
+ return dest;
+ }
+
+ public Vector3f transformPositiveZ(Vector3f dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double xz = x * z;
+ double yw = y * w;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = (float) (yw + xz + xz + yw);
+ dest.y = (float) (yz + yz - xw - xw);
+ dest.z = (float) (zz - yy - xx + ww);
+ return dest;
+ }
+
+ public Vector4f transformPositiveZ(Vector4f dest) {
+ double ww = w * w;
+ double xx = x * x;
+ double yy = y * y;
+ double zz = z * z;
+ double xz = x * z;
+ double yw = y * w;
+ double yz = y * z;
+ double xw = x * w;
+ dest.x = (float) (yw + xz + xz + yw);
+ dest.y = (float) (yz + yz - xw - xw);
+ dest.z = (float) (zz - yy - xx + ww);
+ return dest;
+ }
+
+ public Vector4f transformUnitPositiveZ(Vector4f dest) {
+ double xx = x * x;
+ double yy = y * y;
+ double xz = x * z;
+ double yz = y * z;
+ double xw = x * w;
+ double yw = y * w;
+ dest.x = (float) (xz + yw + xz + yw);
+ dest.y = (float) (yz + yz - xw - xw);
+ dest.z = (float) (1.0 - xx - xx - yy - yy);
+ return dest;
+ }
+
+ public Vector3f transformUnitPositiveZ(Vector3f dest) {
+ double xx = x * x;
+ double yy = y * y;
+ double xz = x * z;
+ double yz = y * z;
+ double xw = x * w;
+ double yw = y * w;
+ dest.x = (float) (xz + yw + xz + yw);
+ dest.y = (float) (yz + yz - xw - xw);
+ dest.z = (float) (1.0 - xx - xx - yy - yy);
+ return dest;
+ }
+
+ public Vector4f transform(Vector4f vec){
+ return transform(vec, vec);
+ }
+
+ public Vector4f transformInverse(Vector4f vec){
+ return transformInverse(vec, vec);
+ }
+
+ public Vector3f transform(Vector3fc vec, Vector3f dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transformInverse(Vector3fc vec, Vector3f dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transform(double x, double y, double z, Vector3f dest) {
+ double xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ double xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ double zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3f transformInverse(double x, double y, double z, Vector3f dest) {
+ double n = 1.0 / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ double qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ double xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ double xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ double zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector4f transform(Vector4fc vec, Vector4f dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transformInverse(Vector4fc vec, Vector4f dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transform(double x, double y, double z, Vector4f dest) {
+ double xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ double xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ double zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set((float) Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ (float) Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ (float) Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)), dest.w);
+ }
+
+ public Vector4f transformInverse(double x, double y, double z, Vector4f dest) {
+ double n = 1.0 / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ double qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ double xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ double xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ double zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)), dest.w);
+ }
+
+ public Vector4f transformUnit(Vector4f vec){
+ return transformUnit(vec, vec);
+ }
+
+ public Vector4f transformInverseUnit(Vector4f vec){
+ return transformInverseUnit(vec, vec);
+ }
+
+ public Vector3f transformUnit(Vector3fc vec, Vector3f dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transformInverseUnit(Vector3fc vec, Vector3f dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transformUnit(double x, double y, double z, Vector3f dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set((float) Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ (float) Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ (float) Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector3f transformInverseUnit(double x, double y, double z, Vector3f dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set((float) Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ (float) Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ (float) Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4f transformUnit(Vector4fc vec, Vector4f dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transformInverseUnit(Vector4fc vec, Vector4f dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transformUnit(double x, double y, double z, Vector4f dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set((float) Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ (float) Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ (float) Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4f transformInverseUnit(double x, double y, double z, Vector4f dest) {
+ double xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ double xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ double yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set((float) Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ (float) Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ (float) Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Quaterniond invert(Quaterniond dest) {
+ double invNorm = 1.0 / lengthSquared();
+ dest.x = -x * invNorm;
+ dest.y = -y * invNorm;
+ dest.z = -z * invNorm;
+ dest.w = w * invNorm;
+ return dest;
+ }
+
+ /**
+ * Invert this quaternion and {@link #normalize() normalize} it.
+ *
+ * If this quaternion is already normalized, then {@link #conjugate()} should be used instead.
+ *
+ * @see #conjugate()
+ *
+ * @return this
+ */
+ public Quaterniond invert() {
+ return invert(this);
+ }
+
+ public Quaterniond div(Quaterniondc b, Quaterniond dest) {
+ double invNorm = 1.0 / Math.fma(b.x(), b.x(), Math.fma(b.y(), b.y(), Math.fma(b.z(), b.z(), b.w() * b.w())));
+ double x = -b.x() * invNorm;
+ double y = -b.y() * invNorm;
+ double z = -b.z() * invNorm;
+ double w = b.w() * invNorm;
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Divide this
quaternion by b
.
+ *
+ * The division expressed using the inverse is performed in the following way:
+ *
+ * this = this * b^-1
, where b^-1
is the inverse of b
.
+ *
+ * @param b
+ * the {@link Quaterniondc} to divide this by
+ * @return this
+ */
+ public Quaterniond div(Quaterniondc b) {
+ return div(b, this);
+ }
+
+ /**
+ * Conjugate this quaternion.
+ *
+ * @return this
+ */
+ public Quaterniond conjugate() {
+ x = -x;
+ y = -y;
+ z = -z;
+ return this;
+ }
+
+ public Quaterniond conjugate(Quaterniond dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ dest.w = w;
+ return dest;
+ }
+
+ /**
+ * Set this quaternion to the identity.
+ *
+ * @return this
+ */
+ public Quaterniond identity() {
+ x = 0.0;
+ y = 0.0;
+ z = 0.0;
+ w = 1.0;
+ return this;
+ }
+
+ public double lengthSquared() {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ /**
+ * Set this quaternion from the supplied euler angles (in radians) with rotation order XYZ.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * Reference: this stackexchange answer
+ *
+ * @param angleX
+ * the angle in radians to rotate about x
+ * @param angleY
+ * the angle in radians to rotate about y
+ * @param angleZ
+ * the angle in radians to rotate about z
+ * @return this
+ */
+ public Quaterniond rotationXYZ(double angleX, double angleY, double angleZ) {
+ double sx = Math.sin(angleX * 0.5);
+ double cx = Math.cosFromSin(sx, angleX * 0.5);
+ double sy = Math.sin(angleY * 0.5);
+ double cy = Math.cosFromSin(sy, angleY * 0.5);
+ double sz = Math.sin(angleZ * 0.5);
+ double cz = Math.cosFromSin(sz, angleZ * 0.5);
+
+ double cycz = cy * cz;
+ double sysz = sy * sz;
+ double sycz = sy * cz;
+ double cysz = cy * sz;
+ w = cx*cycz - sx*sysz;
+ x = sx*cycz + cx*sysz;
+ y = cx*sycz - sx*cysz;
+ z = cx*cysz + sx*sycz;
+
+ return this;
+ }
+
+ /**
+ * Set this quaternion from the supplied euler angles (in radians) with rotation order ZYX.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * Reference: this stackexchange answer
+ *
+ * @param angleX
+ * the angle in radians to rotate about x
+ * @param angleY
+ * the angle in radians to rotate about y
+ * @param angleZ
+ * the angle in radians to rotate about z
+ * @return this
+ */
+ public Quaterniond rotationZYX(double angleZ, double angleY, double angleX) {
+ double sx = Math.sin(angleX * 0.5);
+ double cx = Math.cosFromSin(sx, angleX * 0.5);
+ double sy = Math.sin(angleY * 0.5);
+ double cy = Math.cosFromSin(sy, angleY * 0.5);
+ double sz = Math.sin(angleZ * 0.5);
+ double cz = Math.cosFromSin(sz, angleZ * 0.5);
+
+ double cycz = cy * cz;
+ double sysz = sy * sz;
+ double sycz = sy * cz;
+ double cysz = cy * sz;
+ w = cx*cycz + sx*sysz;
+ x = sx*cycz - cx*sysz;
+ y = cx*sycz + sx*cysz;
+ z = cx*cysz - sx*sycz;
+
+ return this;
+ }
+
+ /**
+ * Set this quaternion from the supplied euler angles (in radians) with rotation order YXZ.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * Reference: https://en.wikipedia.org
+ *
+ * @param angleY
+ * the angle in radians to rotate about y
+ * @param angleX
+ * the angle in radians to rotate about x
+ * @param angleZ
+ * the angle in radians to rotate about z
+ * @return this
+ */
+ public Quaterniond rotationYXZ(double angleY, double angleX, double angleZ) {
+ double sx = Math.sin(angleX * 0.5);
+ double cx = Math.cosFromSin(sx, angleX * 0.5);
+ double sy = Math.sin(angleY * 0.5);
+ double cy = Math.cosFromSin(sy, angleY * 0.5);
+ double sz = Math.sin(angleZ * 0.5);
+ double cz = Math.cosFromSin(sz, angleZ * 0.5);
+
+ double x = cy * sx;
+ double y = sy * cx;
+ double z = sy * sx;
+ double w = cy * cx;
+ this.x = x * cz + y * sz;
+ this.y = y * cz - x * sz;
+ this.z = w * sz - z * cz;
+ this.w = w * cz + z * sz;
+
+ return this;
+ }
+
+ /**
+ * Interpolate between this
{@link #normalize() unit} quaternion and the specified
+ * target
{@link #normalize() unit} quaternion using spherical linear interpolation using the specified interpolation factor alpha
.
+ *
+ * This method resorts to non-spherical linear interpolation when the absolute dot product between this
and target
is
+ * below 1E-6
.
+ *
+ * @param target
+ * the target of the interpolation, which should be reached with alpha = 1.0
+ * @param alpha
+ * the interpolation factor, within [0..1]
+ * @return this
+ */
+ public Quaterniond slerp(Quaterniondc target, double alpha) {
+ return slerp(target, alpha, this);
+ }
+
+ public Quaterniond slerp(Quaterniondc target, double alpha, Quaterniond dest) {
+ double cosom = Math.fma(x, target.x(), Math.fma(y, target.y(), Math.fma(z, target.z(), w * target.w())));
+ double absCosom = Math.abs(cosom);
+ double scale0, scale1;
+ if (1.0 - absCosom > 1E-6) {
+ double sinSqr = 1.0 - absCosom * absCosom;
+ double sinom = Math.invsqrt(sinSqr);
+ double omega = Math.atan2(sinSqr * sinom, absCosom);
+ scale0 = Math.sin((1.0 - alpha) * omega) * sinom;
+ scale1 = Math.sin(alpha * omega) * sinom;
+ } else {
+ scale0 = 1.0 - alpha;
+ scale1 = alpha;
+ }
+ scale1 = cosom >= 0.0 ? scale1 : -scale1;
+ dest.x = Math.fma(scale0, x, scale1 * target.x());
+ dest.y = Math.fma(scale0, y, scale1 * target.y());
+ dest.z = Math.fma(scale0, z, scale1 * target.z());
+ dest.w = Math.fma(scale0, w, scale1 * target.w());
+ return dest;
+ }
+
+ /**
+ * Interpolate between all of the quaternions given in qs
via spherical linear interpolation using the specified interpolation factors weights
,
+ * and store the result in dest
.
+ *
+ * This method will interpolate between each two successive quaternions via {@link #slerp(Quaterniondc, double)} using their relative interpolation weights.
+ *
+ * This method resorts to non-spherical linear interpolation when the absolute dot product of any two interpolated quaternions is below 1E-6f
.
+ *
+ * Reference: http://gamedev.stackexchange.com/
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Quaterniondc slerp(Quaterniond[] qs, double[] weights, Quaterniond dest) {
+ dest.set(qs[0]);
+ double w = weights[0];
+ for (int i = 1; i < qs.length; i++) {
+ double w0 = w;
+ double w1 = weights[i];
+ double rw1 = w1 / (w0 + w1);
+ w += w1;
+ dest.slerp(qs[i], rw1);
+ }
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this quaternion, which results in any vector transformed by this quaternion to change
+ * its length by the given factor
.
+ *
+ * @param factor
+ * the scaling factor
+ * @return this
+ */
+ public Quaterniond scale(double factor) {
+ return scale(factor, this);
+ }
+
+ public Quaterniond scale(double factor, Quaterniond dest) {
+ double sqrt = Math.sqrt(factor);
+ dest.x = sqrt * x;
+ dest.y = sqrt * y;
+ dest.z = sqrt * z;
+ dest.w = sqrt * w;
+ return dest;
+ }
+
+ /**
+ * Set this quaternion to represent scaling, which results in a transformed vector to change
+ * its length by the given factor
.
+ *
+ * @param factor
+ * the scaling factor
+ * @return this
+ */
+ public Quaterniond scaling(double factor) {
+ double sqrt = Math.sqrt(factor);
+ this.x = 0.0;
+ this.y = 0.0;
+ this.z = 0.0;
+ this.w = sqrt;
+ return this;
+ }
+
+ /**
+ * Integrate the rotation given by the angular velocity (vx, vy, vz)
around the x, y and z axis, respectively,
+ * with respect to the given elapsed time delta dt
and add the differentiate rotation to the rotation represented by this quaternion.
+ *
+ * This method pre-multiplies the rotation given by dt
and (vx, vy, vz)
by this
, so
+ * the angular velocities are always relative to the local coordinate system of the rotation represented by this
quaternion.
+ *
+ * This method is equivalent to calling: rotateLocal(dt * vx, dt * vy, dt * vz)
+ *
+ * Reference: http://physicsforgames.blogspot.de/
+ *
+ * @param dt
+ * the delta time
+ * @param vx
+ * the angular velocity around the x axis
+ * @param vy
+ * the angular velocity around the y axis
+ * @param vz
+ * the angular velocity around the z axis
+ * @return this
+ */
+ public Quaterniond integrate(double dt, double vx, double vy, double vz) {
+ return integrate(dt, vx, vy, vz, this);
+ }
+
+ public Quaterniond integrate(double dt, double vx, double vy, double vz, Quaterniond dest) {
+ double thetaX = dt * vx * 0.5;
+ double thetaY = dt * vy * 0.5;
+ double thetaZ = dt * vz * 0.5;
+ double thetaMagSq = thetaX * thetaX + thetaY * thetaY + thetaZ * thetaZ;
+ double s;
+ double dqX, dqY, dqZ, dqW;
+ if (thetaMagSq * thetaMagSq / 24.0 < 1E-8) {
+ dqW = 1.0 - thetaMagSq * 0.5;
+ s = 1.0 - thetaMagSq / 6.0;
+ } else {
+ double thetaMag = Math.sqrt(thetaMagSq);
+ double sin = Math.sin(thetaMag);
+ s = sin / thetaMag;
+ dqW = Math.cosFromSin(sin, thetaMag);
+ }
+ dqX = thetaX * s;
+ dqY = thetaY * s;
+ dqZ = thetaZ * s;
+ /* Pre-multiplication */
+ return dest.set(Math.fma(dqW, x, Math.fma(dqX, w, Math.fma(dqY, z, -dqZ * y))),
+ Math.fma(dqW, y, Math.fma(-dqX, z, Math.fma(dqY, w, dqZ * x))),
+ Math.fma(dqW, z, Math.fma(dqX, y, Math.fma(-dqY, x, dqZ * w))),
+ Math.fma(dqW, w, Math.fma(-dqX, x, Math.fma(-dqY, y, -dqZ * z))));
+ }
+
+ /**
+ * Compute a linear (non-spherical) interpolation of this
and the given quaternion q
+ * and store the result in this
.
+ *
+ * @param q
+ * the other quaternion
+ * @param factor
+ * the interpolation factor. It is between 0.0 and 1.0
+ * @return this
+ */
+ public Quaterniond nlerp(Quaterniondc q, double factor) {
+ return nlerp(q, factor, this);
+ }
+
+ public Quaterniond nlerp(Quaterniondc q, double factor, Quaterniond dest) {
+ double cosom = Math.fma(x, q.x(), Math.fma(y, q.y(), Math.fma(z, q.z(), w * q.w())));
+ double scale0 = 1.0 - factor;
+ double scale1 = (cosom >= 0.0) ? factor : -factor;
+ dest.x = Math.fma(scale0, x, scale1 * q.x());
+ dest.y = Math.fma(scale0, y, scale1 * q.y());
+ dest.z = Math.fma(scale0, z, scale1 * q.z());
+ dest.w = Math.fma(scale0, w, scale1 * q.w());
+ double s = Math.invsqrt(Math.fma(dest.x, dest.x, Math.fma(dest.y, dest.y, Math.fma(dest.z, dest.z, dest.w * dest.w))));
+ dest.x *= s;
+ dest.y *= s;
+ dest.z *= s;
+ dest.w *= s;
+ return dest;
+ }
+
+ /**
+ * Interpolate between all of the quaternions given in qs
via non-spherical linear interpolation using the
+ * specified interpolation factors weights
, and store the result in dest
.
+ *
+ * This method will interpolate between each two successive quaternions via {@link #nlerp(Quaterniondc, double)}
+ * using their relative interpolation weights.
+ *
+ * Reference: http://gamedev.stackexchange.com/
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Quaterniondc nlerp(Quaterniond[] qs, double[] weights, Quaterniond dest) {
+ dest.set(qs[0]);
+ double w = weights[0];
+ for (int i = 1; i < qs.length; i++) {
+ double w0 = w;
+ double w1 = weights[i];
+ double rw1 = w1 / (w0 + w1);
+ w += w1;
+ dest.nlerp(qs[i], rw1);
+ }
+ return dest;
+ }
+
+ public Quaterniond nlerpIterative(Quaterniondc q, double alpha, double dotThreshold, Quaterniond dest) {
+ double q1x = x, q1y = y, q1z = z, q1w = w;
+ double q2x = q.x(), q2y = q.y(), q2z = q.z(), q2w = q.w();
+ double dot = Math.fma(q1x, q2x, Math.fma(q1y, q2y, Math.fma(q1z, q2z, q1w * q2w)));
+ double absDot = Math.abs(dot);
+ if (1.0 - 1E-6 < absDot) {
+ return dest.set(this);
+ }
+ double alphaN = alpha;
+ while (absDot < dotThreshold) {
+ double scale0 = 0.5;
+ double scale1 = dot >= 0.0 ? 0.5 : -0.5;
+ if (alphaN < 0.5) {
+ q2x = Math.fma(scale0, q2x, scale1 * q1x);
+ q2y = Math.fma(scale0, q2y, scale1 * q1y);
+ q2z = Math.fma(scale0, q2z, scale1 * q1z);
+ q2w = Math.fma(scale0, q2w, scale1 * q1w);
+ float s = (float) Math.invsqrt(Math.fma(q2x, q2x, Math.fma(q2y, q2y, Math.fma(q2z, q2z, q2w * q2w))));
+ q2x *= s;
+ q2y *= s;
+ q2z *= s;
+ q2w *= s;
+ alphaN = alphaN + alphaN;
+ } else {
+ q1x = Math.fma(scale0, q1x, scale1 * q2x);
+ q1y = Math.fma(scale0, q1y, scale1 * q2y);
+ q1z = Math.fma(scale0, q1z, scale1 * q2z);
+ q1w = Math.fma(scale0, q1w, scale1 * q2w);
+ float s = (float) Math.invsqrt(Math.fma(q1x, q1x, Math.fma(q1y, q1y, Math.fma(q1z, q1z, q1w * q1w))));
+ q1x *= s;
+ q1y *= s;
+ q1z *= s;
+ q1w *= s;
+ alphaN = alphaN + alphaN - 1.0;
+ }
+ dot = Math.fma(q1x, q2x, Math.fma(q1y, q2y, Math.fma(q1z, q2z, q1w * q2w)));
+ absDot = Math.abs(dot);
+ }
+ double scale0 = 1.0 - alphaN;
+ double scale1 = dot >= 0.0 ? alphaN : -alphaN;
+ double resX = Math.fma(scale0, q1x, scale1 * q2x);
+ double resY = Math.fma(scale0, q1y, scale1 * q2y);
+ double resZ = Math.fma(scale0, q1z, scale1 * q2z);
+ double resW = Math.fma(scale0, q1w, scale1 * q2w);
+ double s = Math.invsqrt(Math.fma(resX, resX, Math.fma(resY, resY, Math.fma(resZ, resZ, resW * resW))));
+ dest.x = resX * s;
+ dest.y = resY * s;
+ dest.z = resZ * s;
+ dest.w = resW * s;
+ return dest;
+ }
+
+ /**
+ * Compute linear (non-spherical) interpolations of this
and the given quaternion q
+ * iteratively and store the result in this
.
+ *
+ * This method performs a series of small-step nlerp interpolations to avoid doing a costly spherical linear interpolation, like
+ * {@link #slerp(Quaterniondc, double, Quaterniond) slerp},
+ * by subdividing the rotation arc between this
and q
via non-spherical linear interpolations as long as
+ * the absolute dot product of this
and q
is greater than the given dotThreshold
parameter.
+ *
+ * Thanks to @theagentd
at http://www.java-gaming.org/ for providing the code.
+ *
+ * @param q
+ * the other quaternion
+ * @param alpha
+ * the interpolation factor, between 0.0 and 1.0
+ * @param dotThreshold
+ * the threshold for the dot product of this
and q
above which this method performs another iteration
+ * of a small-step linear interpolation
+ * @return this
+ */
+ public Quaterniond nlerpIterative(Quaterniondc q, double alpha, double dotThreshold) {
+ return nlerpIterative(q, alpha, dotThreshold, this);
+ }
+
+ /**
+ * Interpolate between all of the quaternions given in qs
via iterative non-spherical linear interpolation using the
+ * specified interpolation factors weights
, and store the result in dest
.
+ *
+ * This method will interpolate between each two successive quaternions via {@link #nlerpIterative(Quaterniondc, double, double)}
+ * using their relative interpolation weights.
+ *
+ * Reference: http://gamedev.stackexchange.com/
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param dotThreshold
+ * the threshold for the dot product of each two interpolated quaternions above which {@link #nlerpIterative(Quaterniondc, double, double)} performs another iteration
+ * of a small-step linear interpolation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Quaterniond nlerpIterative(Quaterniondc[] qs, double[] weights, double dotThreshold, Quaterniond dest) {
+ dest.set(qs[0]);
+ double w = weights[0];
+ for (int i = 1; i < qs.length; i++) {
+ double w0 = w;
+ double w1 = weights[i];
+ double rw1 = w1 / (w0 + w1);
+ w += w1;
+ dest.nlerpIterative(qs[i], rw1, dotThreshold);
+ }
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @see #lookAlong(double, double, double, double, double, double, Quaterniond)
+ *
+ * @param dir
+ * the direction to map to the positive Z axis
+ * @param up
+ * the vector which will be mapped to a vector parallel to the plane
+ * spanned by the given dir
and up
+ * @return this
+ */
+ public Quaterniond lookAlong(Vector3dc dir, Vector3dc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ public Quaterniond lookAlong(Vector3dc dir, Vector3dc up, Quaterniond dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @see #lookAlong(double, double, double, double, double, double, Quaterniond)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Quaterniond lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ public Quaterniond lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Quaterniond dest) {
+ // Normalize direction
+ double invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ double dirnX = -dirX * invDirLength;
+ double dirnY = -dirY * invDirLength;
+ double dirnZ = -dirZ * invDirLength;
+ // left = up x dir
+ double leftX, leftY, leftZ;
+ leftX = upY * dirnZ - upZ * dirnY;
+ leftY = upZ * dirnX - upX * dirnZ;
+ leftZ = upX * dirnY - upY * dirnX;
+ // normalize left
+ double invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ double upnX = dirnY * leftZ - dirnZ * leftY;
+ double upnY = dirnZ * leftX - dirnX * leftZ;
+ double upnZ = dirnX * leftY - dirnY * leftX;
+
+ /* Convert orthonormal basis vectors to quaternion */
+ double x, y, z, w;
+ double t;
+ double tr = leftX + upnY + dirnZ;
+ if (tr >= 0.0) {
+ t = Math.sqrt(tr + 1.0);
+ w = t * 0.5;
+ t = 0.5 / t;
+ x = (dirnY - upnZ) * t;
+ y = (leftZ - dirnX) * t;
+ z = (upnX - leftY) * t;
+ } else {
+ if (leftX > upnY && leftX > dirnZ) {
+ t = Math.sqrt(1.0 + leftX - upnY - dirnZ);
+ x = t * 0.5;
+ t = 0.5 / t;
+ y = (leftY + upnX) * t;
+ z = (dirnX + leftZ) * t;
+ w = (dirnY - upnZ) * t;
+ } else if (upnY > dirnZ) {
+ t = Math.sqrt(1.0 + upnY - leftX - dirnZ);
+ y = t * 0.5;
+ t = 0.5 / t;
+ x = (leftY + upnX) * t;
+ z = (upnZ + dirnY) * t;
+ w = (leftZ - dirnX) * t;
+ } else {
+ t = Math.sqrt(1.0 + dirnZ - leftX - upnY);
+ z = t * 0.5;
+ t = 0.5 / t;
+ x = (dirnX + leftZ) * t;
+ y = (upnZ + dirnY) * t;
+ w = (upnX - leftY) * t;
+ }
+ }
+ /* Multiply */
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Return a string representation of this quaternion.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this quaternion by formatting the components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the quaternion components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + " " + Runtime.format(z, formatter) + " " + Runtime.format(w, formatter) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(x);
+ out.writeDouble(y);
+ out.writeDouble(z);
+ out.writeDouble(w);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ x = in.readDouble();
+ y = in.readDouble();
+ z = in.readDouble();
+ w = in.readDouble();
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(w);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(x);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(y);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(z);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Quaterniond other = (Quaterniond) obj;
+ if (Double.doubleToLongBits(w) != Double.doubleToLongBits(other.w))
+ return false;
+ if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
+ return false;
+ if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
+ return false;
+ if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
+ return false;
+ return true;
+ }
+
+ /**
+ * Compute the difference between this
and the other
quaternion
+ * and store the result in this
.
+ *
+ * The difference is the rotation that has to be applied to get from
+ * this
rotation to other
. If T
is this
, Q
+ * is other
and D
is the computed difference, then the following equation holds:
+ *
+ * T * D = Q
+ *
+ * It is defined as: D = T^-1 * Q
, where T^-1
denotes the {@link #invert() inverse} of T
.
+ *
+ * @param other
+ * the other quaternion
+ * @return this
+ */
+ public Quaterniond difference(Quaterniondc other) {
+ return difference(other, this);
+ }
+
+ public Quaterniond difference(Quaterniondc other, Quaterniond dest) {
+ double invNorm = 1.0 / lengthSquared();
+ double x = -this.x * invNorm;
+ double y = -this.y * invNorm;
+ double z = -this.z * invNorm;
+ double w = this.w * invNorm;
+ dest.set(Math.fma(w, other.x(), Math.fma(x, other.w(), Math.fma(y, other.z(), -z * other.y()))),
+ Math.fma(w, other.y(), Math.fma(-x, other.z(), Math.fma(y, other.w(), z * other.x()))),
+ Math.fma(w, other.z(), Math.fma(x, other.y(), Math.fma(-y, other.x(), z * other.w()))),
+ Math.fma(w, other.w(), Math.fma(-x, other.x(), Math.fma(-y, other.y(), -z * other.z()))));
+ return dest;
+ }
+
+ /**
+ * Set this
quaternion to a rotation that rotates the fromDir
vector to point along toDir
.
+ *
+ * Since there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * Reference: stackoverflow.com
+ *
+ * @param fromDirX
+ * the x-coordinate of the direction to rotate into the destination direction
+ * @param fromDirY
+ * the y-coordinate of the direction to rotate into the destination direction
+ * @param fromDirZ
+ * the z-coordinate of the direction to rotate into the destination direction
+ * @param toDirX
+ * the x-coordinate of the direction to rotate to
+ * @param toDirY
+ * the y-coordinate of the direction to rotate to
+ * @param toDirZ
+ * the z-coordinate of the direction to rotate to
+ * @return this
+ */
+ public Quaterniond rotationTo(double fromDirX, double fromDirY, double fromDirZ, double toDirX, double toDirY, double toDirZ) {
+ double fn = Math.invsqrt(Math.fma(fromDirX, fromDirX, Math.fma(fromDirY, fromDirY, fromDirZ * fromDirZ)));
+ double tn = Math.invsqrt(Math.fma(toDirX, toDirX, Math.fma(toDirY, toDirY, toDirZ * toDirZ)));
+ double fx = fromDirX * fn, fy = fromDirY * fn, fz = fromDirZ * fn;
+ double tx = toDirX * tn, ty = toDirY * tn, tz = toDirZ * tn;
+ double dot = fx * tx + fy * ty + fz * tz;
+ double x, y, z, w;
+ if (dot < -1.0 + 1E-6) {
+ x = fy;
+ y = -fx;
+ z = 0.0;
+ w = 0.0;
+ if (x * x + y * y == 0.0) {
+ x = 0.0;
+ y = fz;
+ z = -fy;
+ w = 0.0;
+ }
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = 0;
+ } else {
+ double sd2 = Math.sqrt((1.0 + dot) * 2.0);
+ double isd2 = 1.0 / sd2;
+ double cx = fy * tz - fz * ty;
+ double cy = fz * tx - fx * tz;
+ double cz = fx * ty - fy * tx;
+ x = cx * isd2;
+ y = cy * isd2;
+ z = cz * isd2;
+ w = sd2 * 0.5;
+ double n2 = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ this.x = x * n2;
+ this.y = y * n2;
+ this.z = z * n2;
+ this.w = w * n2;
+ }
+ return this;
+ }
+
+ /**
+ * Set this
quaternion to a rotation that rotates the fromDir
vector to point along toDir
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * @see #rotationTo(double, double, double, double, double, double)
+ *
+ * @param fromDir
+ * the starting direction
+ * @param toDir
+ * the destination direction
+ * @return this
+ */
+ public Quaterniond rotationTo(Vector3dc fromDir, Vector3dc toDir) {
+ return rotationTo(fromDir.x(), fromDir.y(), fromDir.z(), toDir.x(), toDir.y(), toDir.z());
+ }
+
+ public Quaterniond rotateTo(double fromDirX, double fromDirY, double fromDirZ,
+ double toDirX, double toDirY, double toDirZ, Quaterniond dest) {
+ double fn = Math.invsqrt(Math.fma(fromDirX, fromDirX, Math.fma(fromDirY, fromDirY, fromDirZ * fromDirZ)));
+ double tn = Math.invsqrt(Math.fma(toDirX, toDirX, Math.fma(toDirY, toDirY, toDirZ * toDirZ)));
+ double fx = fromDirX * fn, fy = fromDirY * fn, fz = fromDirZ * fn;
+ double tx = toDirX * tn, ty = toDirY * tn, tz = toDirZ * tn;
+ double dot = fx * tx + fy * ty + fz * tz;
+ double x, y, z, w;
+ if (dot < -1.0 + 1E-6) {
+ x = fy;
+ y = -fx;
+ z = 0.0;
+ w = 0.0;
+ if (x * x + y * y == 0.0) {
+ x = 0.0;
+ y = fz;
+ z = -fy;
+ w = 0.0;
+ }
+ } else {
+ double sd2 = Math.sqrt((1.0 + dot) * 2.0);
+ double isd2 = 1.0 / sd2;
+ double cx = fy * tz - fz * ty;
+ double cy = fz * tx - fx * tz;
+ double cz = fx * ty - fy * tx;
+ x = cx * isd2;
+ y = cy * isd2;
+ z = cz * isd2;
+ w = sd2 * 0.5;
+ double n2 = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ x *= n2;
+ y *= n2;
+ z *= n2;
+ w *= n2;
+ }
+ /* Multiply */
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Set this {@link Quaterniond} to a rotation of the given angle in radians about the supplied
+ * axis, all of which are specified via the {@link AxisAngle4f}.
+ *
+ * @see #rotationAxis(double, double, double, double)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} giving the rotation angle in radians and the axis to rotate about
+ * @return this
+ */
+ public Quaterniond rotationAxis(AxisAngle4f axisAngle) {
+ return rotationAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this quaternion to a rotation of the given angle in radians about the supplied axis.
+ *
+ * @param angle
+ * the rotation angle in radians
+ * @param axisX
+ * the x-coordinate of the rotation axis
+ * @param axisY
+ * the y-coordinate of the rotation axis
+ * @param axisZ
+ * the z-coordinate of the rotation axis
+ * @return this
+ */
+ public Quaterniond rotationAxis(double angle, double axisX, double axisY, double axisZ) {
+ double hangle = angle / 2.0;
+ double sinAngle = Math.sin(hangle);
+ double invVLength = Math.invsqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
+ return set(axisX * invVLength * sinAngle,
+ axisY * invVLength * sinAngle,
+ axisZ * invVLength * sinAngle,
+ Math.cosFromSin(sinAngle, hangle));
+ }
+
+ /**
+ * Set this quaternion to represent a rotation of the given radians about the x axis.
+ *
+ * @param angle
+ * the angle in radians to rotate about the x axis
+ * @return this
+ */
+ public Quaterniond rotationX(double angle) {
+ double sin = Math.sin(angle * 0.5);
+ double cos = Math.cosFromSin(sin, angle * 0.5);
+ return set(sin, 0, cos, 0);
+ }
+
+ /**
+ * Set this quaternion to represent a rotation of the given radians about the y axis.
+ *
+ * @param angle
+ * the angle in radians to rotate about the y axis
+ * @return this
+ */
+ public Quaterniond rotationY(double angle) {
+ double sin = Math.sin(angle * 0.5);
+ double cos = Math.cosFromSin(sin, angle * 0.5);
+ return set(0, sin, 0, cos);
+ }
+
+ /**
+ * Set this quaternion to represent a rotation of the given radians about the z axis.
+ *
+ * @param angle
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaterniond rotationZ(double angle) {
+ double sin = Math.sin(angle * 0.5);
+ double cos = Math.cosFromSin(sin, angle * 0.5);
+ return set(0, 0, sin, cos);
+ }
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
.
+ *
+ * Since there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateTo(double, double, double, double, double, double, Quaterniond)
+ *
+ * @param fromDirX
+ * the x-coordinate of the direction to rotate into the destination direction
+ * @param fromDirY
+ * the y-coordinate of the direction to rotate into the destination direction
+ * @param fromDirZ
+ * the z-coordinate of the direction to rotate into the destination direction
+ * @param toDirX
+ * the x-coordinate of the direction to rotate to
+ * @param toDirY
+ * the y-coordinate of the direction to rotate to
+ * @param toDirZ
+ * the z-coordinate of the direction to rotate to
+ * @return this
+ */
+ public Quaterniond rotateTo(double fromDirX, double fromDirY, double fromDirZ, double toDirX, double toDirY, double toDirZ) {
+ return rotateTo(fromDirX, fromDirY, fromDirZ, toDirX, toDirY, toDirZ, this);
+ }
+
+ public Quaterniond rotateTo(Vector3dc fromDir, Vector3dc toDir, Quaterniond dest) {
+ return rotateTo(fromDir.x(), fromDir.y(), fromDir.z(), toDir.x(), toDir.y(), toDir.z(), dest);
+ }
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateTo(double, double, double, double, double, double, Quaterniond)
+ *
+ * @param fromDir
+ * the starting direction
+ * @param toDir
+ * the destination direction
+ * @return this
+ */
+ public Quaterniond rotateTo(Vector3dc fromDir, Vector3dc toDir) {
+ return rotateTo(fromDir.x(), fromDir.y(), fromDir.z(), toDir.x(), toDir.y(), toDir.z(), this);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the x axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the x axis
+ * @return this
+ */
+ public Quaterniond rotateX(double angle) {
+ return rotateX(angle, this);
+ }
+
+ public Quaterniond rotateX(double angle, Quaterniond dest) {
+ double sin = Math.sin(angle * 0.5);
+ double cos = Math.cosFromSin(sin, angle * 0.5);
+ return dest.set(w * sin + x * cos,
+ y * cos + z * sin,
+ z * cos - y * sin,
+ w * cos - x * sin);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the y axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the y axis
+ * @return this
+ */
+ public Quaterniond rotateY(double angle) {
+ return rotateY(angle, this);
+ }
+
+ public Quaterniond rotateY(double angle, Quaterniond dest) {
+ double sin = Math.sin(angle * 0.5);
+ double cos = Math.cosFromSin(sin, angle * 0.5);
+ return dest.set(x * cos - z * sin,
+ w * sin + y * cos,
+ x * sin + z * cos,
+ w * cos - y * sin);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the z axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaterniond rotateZ(double angle) {
+ return rotateZ(angle, this);
+ }
+
+ public Quaterniond rotateZ(double angle, Quaterniond dest) {
+ double sin = Math.sin(angle * 0.5);
+ double cos = Math.cosFromSin(sin, angle * 0.5);
+ return dest.set(x * cos + y * sin,
+ y * cos - x * sin,
+ w * sin + z * cos,
+ w * cos - z * sin);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local x axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local x axis
+ * @return this
+ */
+ public Quaterniond rotateLocalX(double angle) {
+ return rotateLocalX(angle, this);
+ }
+
+ public Quaterniond rotateLocalX(double angle, Quaterniond dest) {
+ double hangle = angle * 0.5;
+ double s = Math.sin(hangle);
+ double c = Math.cosFromSin(s, hangle);
+ dest.set(c * x + s * w,
+ c * y - s * z,
+ c * z + s * y,
+ c * w - s * x);
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local y axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local y axis
+ * @return this
+ */
+ public Quaterniond rotateLocalY(double angle) {
+ return rotateLocalY(angle, this);
+ }
+
+ public Quaterniond rotateLocalY(double angle, Quaterniond dest) {
+ double hangle = angle * 0.5;
+ double s = Math.sin(hangle);
+ double c = Math.cosFromSin(s, hangle);
+ dest.set(c * x + s * z,
+ c * y + s * w,
+ c * z - s * x,
+ c * w - s * y);
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local z axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local z axis
+ * @return this
+ */
+ public Quaterniond rotateLocalZ(double angle) {
+ return rotateLocalZ(angle, this);
+ }
+
+ public Quaterniond rotateLocalZ(double angle, Quaterniond dest) {
+ double hangle = angle * 0.5;
+ double s = Math.sin(hangle);
+ double c = Math.cosFromSin(s, hangle);
+ dest.set(c * x - s * y,
+ c * y + s * x,
+ c * z + s * w,
+ c * w - s * z);
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles using rotation sequence XYZ
.
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaterniond rotateXYZ(double angleX, double angleY, double angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Quaterniond rotateXYZ(double angleX, double angleY, double angleZ, Quaterniond dest) {
+ double sx = Math.sin(angleX * 0.5);
+ double cx = Math.cosFromSin(sx, angleX * 0.5);
+ double sy = Math.sin(angleY * 0.5);
+ double cy = Math.cosFromSin(sy, angleY * 0.5);
+ double sz = Math.sin(angleZ * 0.5);
+ double cz = Math.cosFromSin(sz, angleZ * 0.5);
+
+ double cycz = cy * cz;
+ double sysz = sy * sz;
+ double sycz = sy * cz;
+ double cysz = cy * sz;
+ double w = cx*cycz - sx*sysz;
+ double x = sx*cycz + cx*sysz;
+ double y = cx*sycz - sx*cysz;
+ double z = cx*cysz + sx*sycz;
+ // right-multiply
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence ZYX
.
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @return this
+ */
+ public Quaterniond rotateZYX(double angleZ, double angleY, double angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Quaterniond rotateZYX(double angleZ, double angleY, double angleX, Quaterniond dest) {
+ double sx = Math.sin(angleX * 0.5);
+ double cx = Math.cosFromSin(sx, angleX * 0.5);
+ double sy = Math.sin(angleY * 0.5);
+ double cy = Math.cosFromSin(sy, angleY * 0.5);
+ double sz = Math.sin(angleZ * 0.5);
+ double cz = Math.cosFromSin(sz, angleZ * 0.5);
+
+ double cycz = cy * cz;
+ double sysz = sy * sz;
+ double sycz = sy * cz;
+ double cysz = cy * sz;
+ double w = cx*cycz + sx*sysz;
+ double x = sx*cycz - cx*sysz;
+ double y = cx*sycz + sx*cysz;
+ double z = cx*cysz - sx*sycz;
+ // right-multiply
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence YXZ
.
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaterniond rotateYXZ(double angleY, double angleX, double angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Quaterniond rotateYXZ(double angleY, double angleX, double angleZ, Quaterniond dest) {
+ double sx = Math.sin(angleX * 0.5);
+ double cx = Math.cosFromSin(sx, angleX * 0.5);
+ double sy = Math.sin(angleY * 0.5);
+ double cy = Math.cosFromSin(sy, angleY * 0.5);
+ double sz = Math.sin(angleZ * 0.5);
+ double cz = Math.cosFromSin(sz, angleZ * 0.5);
+
+ double yx = cy * sx;
+ double yy = sy * cx;
+ double yz = sy * sx;
+ double yw = cy * cx;
+ double x = yx * cz + yy * sz;
+ double y = yy * cz - yx * sz;
+ double z = yw * sz - yz * cz;
+ double w = yw * cz + yz * sz;
+ // right-multiply
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ public Vector3d getEulerAnglesXYZ(Vector3d eulerAngles) {
+ eulerAngles.x = Math.atan2(x * w - y * z, 0.5 - x * x - y * y);
+ eulerAngles.y = Math.safeAsin(2.0 * (x * z + y * w));
+ eulerAngles.z = Math.atan2(z * w - x * y, 0.5 - y * y - z * z);
+ return eulerAngles;
+ }
+
+ public Vector3d getEulerAnglesZYX(Vector3d eulerAngles) {
+ eulerAngles.x = Math.atan2(y * z + w * x, 0.5 - x * x + y * y);
+ eulerAngles.y = Math.safeAsin(-2.0 * (x * z - w * y));
+ eulerAngles.z = Math.atan2(x * y + w * z, 0.5 - y * y - z * z);
+ return eulerAngles;
+ }
+
+ public Quaterniond rotateAxis(double angle, double axisX, double axisY, double axisZ, Quaterniond dest) {
+ double hangle = angle / 2.0;
+ double sinAngle = Math.sin(hangle);
+ double invVLength = Math.invsqrt(Math.fma(axisX, axisX, Math.fma(axisY, axisY, axisZ * axisZ)));
+ double rx = axisX * invVLength * sinAngle;
+ double ry = axisY * invVLength * sinAngle;
+ double rz = axisZ * invVLength * sinAngle;
+ double rw = Math.cosFromSin(sinAngle, hangle);
+ return dest.set(Math.fma(this.w, rx, Math.fma(this.x, rw, Math.fma(this.y, rz, -this.z * ry))),
+ Math.fma(this.w, ry, Math.fma(-this.x, rz, Math.fma(this.y, rw, this.z * rx))),
+ Math.fma(this.w, rz, Math.fma(this.x, ry, Math.fma(-this.y, rx, this.z * rw))),
+ Math.fma(this.w, rw, Math.fma(-this.x, rx, Math.fma(-this.y, ry, -this.z * rz))));
+ }
+
+ public Quaterniond rotateAxis(double angle, Vector3dc axis, Quaterniond dest) {
+ return rotateAxis(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateAxis(double, double, double, double, Quaterniond)
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axis
+ * the rotation axis
+ * @return this
+ */
+ public Quaterniond rotateAxis(double angle, Vector3dc axis) {
+ return rotateAxis(angle, axis.x(), axis.y(), axis.z(), this);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateAxis(double, double, double, double, Quaterniond)
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axisX
+ * the x coordinate of the rotation axis
+ * @param axisY
+ * the y coordinate of the rotation axis
+ * @param axisZ
+ * the z coordinate of the rotation axis
+ * @return this
+ */
+ public Quaterniond rotateAxis(double angle, double axisX, double axisY, double axisZ) {
+ return rotateAxis(angle, axisX, axisY, axisZ, this);
+ }
+
+ public Vector3d positiveX(Vector3d dir) {
+ double invNorm = 1.0 / lengthSquared();
+ double nx = -x * invNorm;
+ double ny = -y * invNorm;
+ double nz = -z * invNorm;
+ double nw = w * invNorm;
+ double dy = ny + ny;
+ double dz = nz + nz;
+ dir.x = -ny * dy - nz * dz + 1.0;
+ dir.y = nx * dy + nw * dz;
+ dir.z = nx * dz - nw * dy;
+ return dir;
+ }
+
+ public Vector3d normalizedPositiveX(Vector3d dir) {
+ double dy = y + y;
+ double dz = z + z;
+ dir.x = -y * dy - z * dz + 1.0;
+ dir.y = x * dy - w * dz;
+ dir.z = x * dz + w * dy;
+ return dir;
+ }
+
+ public Vector3d positiveY(Vector3d dir) {
+ double invNorm = 1.0 / lengthSquared();
+ double nx = -x * invNorm;
+ double ny = -y * invNorm;
+ double nz = -z * invNorm;
+ double nw = w * invNorm;
+ double dx = nx + nx;
+ double dy = ny + ny;
+ double dz = nz + nz;
+ dir.x = nx * dy - nw * dz;
+ dir.y = -nx * dx - nz * dz + 1.0;
+ dir.z = ny * dz + nw * dx;
+ return dir;
+ }
+
+ public Vector3d normalizedPositiveY(Vector3d dir) {
+ double dx = x + x;
+ double dy = y + y;
+ double dz = z + z;
+ dir.x = x * dy + w * dz;
+ dir.y = -x * dx - z * dz + 1.0;
+ dir.z = y * dz - w * dx;
+ return dir;
+ }
+
+ public Vector3d positiveZ(Vector3d dir) {
+ double invNorm = 1.0 / lengthSquared();
+ double nx = -x * invNorm;
+ double ny = -y * invNorm;
+ double nz = -z * invNorm;
+ double nw = w * invNorm;
+ double dx = nx + nx;
+ double dy = ny + ny;
+ double dz = nz + nz;
+ dir.x = nx * dz + nw * dy;
+ dir.y = ny * dz - nw * dx;
+ dir.z = -nx * dx - ny * dy + 1.0;
+ return dir;
+ }
+
+ public Vector3d normalizedPositiveZ(Vector3d dir) {
+ double dx = x + x;
+ double dy = y + y;
+ double dz = z + z;
+ dir.x = x * dz - w * dy;
+ dir.y = y * dz + w * dx;
+ dir.z = -x * dx - y * dy + 1.0;
+ return dir;
+ }
+
+ /**
+ * Conjugate this
by the given quaternion q
by computing q * this * q^-1
.
+ *
+ * @param q
+ * the {@link Quaterniondc} to conjugate this
by
+ * @return this
+ */
+ public Quaterniond conjugateBy(Quaterniondc q) {
+ return conjugateBy(q, this);
+ }
+
+ /**
+ * Conjugate this
by the given quaternion q
by computing q * this * q^-1
+ * and store the result into dest
.
+ *
+ * @param q
+ * the {@link Quaterniondc} to conjugate this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Quaterniond conjugateBy(Quaterniondc q, Quaterniond dest) {
+ double invNorm = 1.0 / q.lengthSquared();
+ double qix = -q.x() * invNorm, qiy = -q.y() * invNorm, qiz = -q.z() * invNorm, qiw = q.w() * invNorm;
+ double qpx = Math.fma(q.w(), x, Math.fma(q.x(), w, Math.fma(q.y(), z, -q.z() * y)));
+ double qpy = Math.fma(q.w(), y, Math.fma(-q.x(), z, Math.fma(q.y(), w, q.z() * x)));
+ double qpz = Math.fma(q.w(), z, Math.fma(q.x(), y, Math.fma(-q.y(), x, q.z() * w)));
+ double qpw = Math.fma(q.w(), w, Math.fma(-q.x(), x, Math.fma(-q.y(), y, -q.z() * z)));
+ return dest.set(Math.fma(qpw, qix, Math.fma(qpx, qiw, Math.fma(qpy, qiz, -qpz * qiy))),
+ Math.fma(qpw, qiy, Math.fma(-qpx, qiz, Math.fma(qpy, qiw, qpz * qix))),
+ Math.fma(qpw, qiz, Math.fma(qpx, qiy, Math.fma(-qpy, qix, qpz * qiw))),
+ Math.fma(qpw, qiw, Math.fma(-qpx, qix, Math.fma(-qpy, qiy, -qpz * qiz))));
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z) && Math.isFinite(w);
+ }
+
+ public boolean equals(Quaterniondc q, double delta) {
+ if (this == q)
+ return true;
+ if (q == null)
+ return false;
+ if (!(q instanceof Quaterniondc))
+ return false;
+ if (!Runtime.equals(x, q.x(), delta))
+ return false;
+ if (!Runtime.equals(y, q.y(), delta))
+ return false;
+ if (!Runtime.equals(z, q.z(), delta))
+ return false;
+ if (!Runtime.equals(w, q.w(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(double x, double y, double z, double w) {
+ if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(x))
+ return false;
+ if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(y))
+ return false;
+ if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(z))
+ return false;
+ if (Double.doubleToLongBits(this.w) != Double.doubleToLongBits(w))
+ return false;
+ return true;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/QuaterniondInterpolator.java b/src/main/java/com/jozufozu/flywheel/repack/joml/QuaterniondInterpolator.java
new file mode 100644
index 000000000..6329c4540
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/QuaterniondInterpolator.java
@@ -0,0 +1,354 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Computes the weighted average of multiple rotations represented as {@link Quaterniond} instances.
+ *
+ * Instances of this class are not thread-safe.
+ *
+ * @author Kai Burjack
+ */
+public class QuaterniondInterpolator {
+
+ /**
+ * Performs singular value decomposition on {@link Matrix3d}.
+ *
+ * This code was adapted from http://www.public.iastate.edu/.
+ *
+ * @author Kai Burjack
+ */
+ private static class SvdDecomposition3d {
+ private final double rv1[];
+ private final double w[];
+ private final double v[];
+
+ SvdDecomposition3d() {
+ this.rv1 = new double[3];
+ this.w = new double[3];
+ this.v = new double[9];
+ }
+
+ private double SIGN(double a, double b) {
+ return (b) >= 0.0 ? Math.abs(a) : -Math.abs(a);
+ }
+
+ void svd(double[] a, int maxIterations, Matrix3d destU, Matrix3d destV) {
+ int flag, i, its, j, jj, k, l = 0, nm = 0;
+ double c, f, h, s, x, y, z;
+ double anorm = 0.0, g = 0.0, scale = 0.0;
+ /* Householder reduction to bidiagonal form */
+ for (i = 0; i < 3; i++) {
+ /* left-hand reduction */
+ l = i + 1;
+ rv1[i] = scale * g;
+ g = s = scale = 0.0;
+ for (k = i; k < 3; k++)
+ scale += Math.abs(a[k + 3 * i]);
+ if (scale != 0.0) {
+ for (k = i; k < 3; k++) {
+ a[k + 3 * i] = (a[k + 3 * i] / scale);
+ s += (a[k + 3 * i] * a[k + 3 * i]);
+ }
+ f = a[i + 3 * i];
+ g = -SIGN(Math.sqrt(s), f);
+ h = f * g - s;
+ a[i + 3 * i] = f - g;
+ if (i != 3 - 1) {
+ for (j = l; j < 3; j++) {
+ for (s = 0.0, k = i; k < 3; k++)
+ s += a[k + 3 * i] * a[k + 3 * j];
+ f = s / h;
+ for (k = i; k < 3; k++)
+ a[k + 3 * j] += f * a[k + 3 * i];
+ }
+ }
+ for (k = i; k < 3; k++)
+ a[k + 3 * i] = a[k + 3 * i] * scale;
+ }
+ w[i] = (scale * g);
+
+ /* right-hand reduction */
+ g = s = scale = 0.0;
+ if (i < 3 && i != 3 - 1) {
+ for (k = l; k < 3; k++)
+ scale += Math.abs(a[i + 3 * k]);
+ if (scale != 0.0) {
+ for (k = l; k < 3; k++) {
+ a[i + 3 * k] = a[i + 3 * k] / scale;
+ s += a[i + 3 * k] * a[i + 3 * k];
+ }
+ f = a[i + 3 * l];
+ g = -SIGN(Math.sqrt(s), f);
+ h = f * g - s;
+ a[i + 3 * l] = f - g;
+ for (k = l; k < 3; k++)
+ rv1[k] = a[i + 3 * k] / h;
+ if (i != 3 - 1) {
+ for (j = l; j < 3; j++) {
+ for (s = 0.0, k = l; k < 3; k++)
+ s += a[j + 3 * k] * a[i + 3 * k];
+ for (k = l; k < 3; k++)
+ a[j + 3 * k] += s * rv1[k];
+ }
+ }
+ for (k = l; k < 3; k++)
+ a[i + 3 * k] = a[i + 3 * k] * scale;
+ }
+ }
+ anorm = Math.max(anorm, (Math.abs(w[i]) + Math.abs(rv1[i])));
+ }
+
+ /* accumulate the right-hand transformation */
+ for (i = 3 - 1; i >= 0; i--) {
+ if (i < 3 - 1) {
+ if (g != 0.0) {
+ for (j = l; j < 3; j++)
+ v[j + 3 * i] = (a[i + 3 * j] / a[i + 3 * l]) / g;
+ /* double division to avoid underflow */
+ for (j = l; j < 3; j++) {
+ for (s = 0.0, k = l; k < 3; k++)
+ s += a[i + 3 * k] * v[k + 3 * j];
+ for (k = l; k < 3; k++)
+ v[k + 3 * j] += s * v[k + 3 * i];
+ }
+ }
+ for (j = l; j < 3; j++)
+ v[i + 3 * j] = v[j + 3 * i] = 0.0;
+ }
+ v[i + 3 * i] = 1.0;
+ g = rv1[i];
+ l = i;
+ }
+
+ /* accumulate the left-hand transformation */
+ for (i = 3 - 1; i >= 0; i--) {
+ l = i + 1;
+ g = w[i];
+ if (i < 3 - 1)
+ for (j = l; j < 3; j++)
+ a[i + 3 * j] = 0.0;
+ if (g != 0.0) {
+ g = 1.0 / g;
+ if (i != 3 - 1) {
+ for (j = l; j < 3; j++) {
+ for (s = 0.0, k = l; k < 3; k++)
+ s += a[k + 3 * i] * a[k + 3 * j];
+ f = s / a[i + 3 * i] * g;
+ for (k = i; k < 3; k++)
+ a[k + 3 * j] += f * a[k + 3 * i];
+ }
+ }
+ for (j = i; j < 3; j++)
+ a[j + 3 * i] = a[j + 3 * i] * g;
+ } else {
+ for (j = i; j < 3; j++)
+ a[j + 3 * i] = 0.0;
+ }
+ ++a[i + 3 * i];
+ }
+
+ /* diagonalize the bidiagonal form */
+ for (k = 3 - 1; k >= 0; k--) { /* loop over singular values */
+ for (its = 0; its < maxIterations; its++) { /* loop over allowed iterations */
+ flag = 1;
+ for (l = k; l >= 0; l--) { /* test for splitting */
+ nm = l - 1;
+ if (Math.abs(rv1[l]) + anorm == anorm) {
+ flag = 0;
+ break;
+ }
+ if (Math.abs(w[nm]) + anorm == anorm)
+ break;
+ }
+ if (flag != 0) {
+ c = 0.0;
+ s = 1.0;
+ for (i = l; i <= k; i++) {
+ f = s * rv1[i];
+ if (Math.abs(f) + anorm != anorm) {
+ g = w[i];
+ h = PYTHAG(f, g);
+ w[i] = h;
+ h = 1.0 / h;
+ c = g * h;
+ s = (-f * h);
+ for (j = 0; j < 3; j++) {
+ y = a[j + 3 * nm];
+ z = a[j + 3 * i];
+ a[j + 3 * nm] = y * c + z * s;
+ a[j + 3 * i] = z * c - y * s;
+ }
+ }
+ }
+ }
+ z = w[k];
+ if (l == k) { /* convergence */
+ if (z < 0.0) { /* make singular value nonnegative */
+ w[k] = -z;
+ for (j = 0; j < 3; j++)
+ v[j + 3 * k] = (-v[j + 3 * k]);
+ }
+ break;
+ }
+ if (its == maxIterations - 1) {
+ throw new RuntimeException("No convergence after " + maxIterations + " iterations");
+ }
+
+ /* shift from bottom 2 x 2 minor */
+ x = w[l];
+ nm = k - 1;
+ y = w[nm];
+ g = rv1[nm];
+ h = rv1[k];
+ f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
+ g = PYTHAG(f, 1.0);
+ f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
+
+ /* next QR transformation */
+ c = s = 1.0;
+ for (j = l; j <= nm; j++) {
+ i = j + 1;
+ g = rv1[i];
+ y = w[i];
+ h = s * g;
+ g = c * g;
+ z = PYTHAG(f, h);
+ rv1[j] = z;
+ c = f / z;
+ s = h / z;
+ f = x * c + g * s;
+ g = g * c - x * s;
+ h = y * s;
+ y = y * c;
+ for (jj = 0; jj < 3; jj++) {
+ x = v[jj + 3 * j];
+ z = v[jj + 3 * i];
+ v[jj + 3 * j] = x * c + z * s;
+ v[jj + 3 * i] = z * c - x * s;
+ }
+ z = PYTHAG(f, h);
+ w[j] = z;
+ if (z != 0.0) {
+ z = 1.0 / z;
+ c = f * z;
+ s = h * z;
+ }
+ f = (c * g) + (s * y);
+ x = (c * y) - (s * g);
+ for (jj = 0; jj < 3; jj++) {
+ y = a[jj + 3 * j];
+ z = a[jj + 3 * i];
+ a[jj + 3 * j] = y * c + z * s;
+ a[jj + 3 * i] = z * c - y * s;
+ }
+ }
+ rv1[l] = 0.0;
+ rv1[k] = f;
+ w[k] = x;
+ }
+ }
+ destU.set(a);
+ destV.set(v);
+ }
+
+ private static double PYTHAG(double a, double b) {
+ double at = Math.abs(a), bt = Math.abs(b), ct, result;
+ if (at > bt) {
+ ct = bt / at;
+ result = at * Math.sqrt(1.0 + ct * ct);
+ } else if (bt > 0.0) {
+ ct = at / bt;
+ result = bt * Math.sqrt(1.0 + ct * ct);
+ } else
+ result = 0.0;
+ return (result);
+ }
+ }
+
+ private final SvdDecomposition3d svdDecomposition3d = new SvdDecomposition3d();
+ private final double[] m = new double[9];
+ private final Matrix3d u = new Matrix3d();
+ private final Matrix3d v = new Matrix3d();
+
+ /**
+ * Compute the weighted average of all of the quaternions given in qs
using the specified interpolation factors weights
, and store the result in dest
.
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param maxSvdIterations
+ * the maximum number of iterations in the Singular Value Decomposition step used by this method
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Quaterniond computeWeightedAverage(Quaterniond[] qs, double[] weights, int maxSvdIterations, Quaterniond dest) {
+ double m00 = 0.0, m01 = 0.0, m02 = 0.0;
+ double m10 = 0.0, m11 = 0.0, m12 = 0.0;
+ double m20 = 0.0, m21 = 0.0, m22 = 0.0;
+ // Sum the rotation matrices of qs
+ for (int i = 0; i < qs.length; i++) {
+ Quaterniond q = qs[i];
+ double dx = q.x + q.x;
+ double dy = q.y + q.y;
+ double dz = q.z + q.z;
+ double q00 = dx * q.x;
+ double q11 = dy * q.y;
+ double q22 = dz * q.z;
+ double q01 = dx * q.y;
+ double q02 = dx * q.z;
+ double q03 = dx * q.w;
+ double q12 = dy * q.z;
+ double q13 = dy * q.w;
+ double q23 = dz * q.w;
+ m00 += weights[i] * (1.0 - q11 - q22);
+ m01 += weights[i] * (q01 + q23);
+ m02 += weights[i] * (q02 - q13);
+ m10 += weights[i] * (q01 - q23);
+ m11 += weights[i] * (1.0 - q22 - q00);
+ m12 += weights[i] * (q12 + q03);
+ m20 += weights[i] * (q02 + q13);
+ m21 += weights[i] * (q12 - q03);
+ m22 += weights[i] * (1.0 - q11 - q00);
+ }
+ m[0] = m00;
+ m[1] = m01;
+ m[2] = m02;
+ m[3] = m10;
+ m[4] = m11;
+ m[5] = m12;
+ m[6] = m20;
+ m[7] = m21;
+ m[8] = m22;
+ // Compute the Singular Value Decomposition of 'm'
+ svdDecomposition3d.svd(m, maxSvdIterations, u, v);
+ // Compute rotation matrix
+ u.mul(v.transpose());
+ // Build quaternion from it
+ return dest.setFromNormalized(u).normalize();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Quaterniondc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaterniondc.java
new file mode 100644
index 000000000..b7eeeffc1
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaterniondc.java
@@ -0,0 +1,1966 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.util.*;
+/**
+ * Interface to a read-only view of a quaternion of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Quaterniondc {
+
+ /**
+ * @return the first component of the vector part
+ */
+ double x();
+
+ /**
+ * @return the second component of the vector part
+ */
+ double y();
+
+ /**
+ * @return the third component of the vector part
+ */
+ double z();
+
+ /**
+ * @return the real/scalar part of the quaternion
+ */
+ double w();
+
+ /**
+ * Normalize this quaternion and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond normalize(Quaterniond dest);
+
+ /**
+ * Add the quaternion (x, y, z, w)
to this quaternion and store the result in dest
.
+ *
+ * @param x
+ * the x component of the vector part
+ * @param y
+ * the y component of the vector part
+ * @param z
+ * the z component of the vector part
+ * @param w
+ * the real/scalar component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond add(double x, double y, double z, double w, Quaterniond dest);
+
+ /**
+ * Add q2
to this quaternion and store the result in dest
.
+ *
+ * @param q2
+ * the quaternion to add to this
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond add(Quaterniondc q2, Quaterniond dest);
+
+ /**
+ * Return the dot product of this {@link Quaterniond} and otherQuat
.
+ *
+ * @param otherQuat
+ * the other quaternion
+ * @return the dot product
+ */
+ double dot(Quaterniondc otherQuat);
+
+ /**
+ * Return the angle in radians represented by this normalized quaternion rotation.
+ *
+ * This quaternion must be {@link #normalize(Quaterniond) normalized}.
+ *
+ * @return the angle in radians
+ */
+ double angle();
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix3d#set(Quaterniondc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix3d get(Matrix3d dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix3f#set(Quaterniondc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix3f get(Matrix3f dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix4d#set(Quaterniondc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix4d get(Matrix4d dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix4f#set(Quaterniondc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix4f get(Matrix4f dest);
+
+ /**
+ * Set the given {@link AxisAngle4f} to represent the rotation of
+ * this
quaternion.
+ *
+ * @param dest
+ * the {@link AxisAngle4f} to set
+ * @return the passed in destination
+ */
+ AxisAngle4f get(AxisAngle4f dest);
+
+ /**
+ * Set the given {@link AxisAngle4d} to represent the rotation of
+ * this
quaternion.
+ *
+ * @param dest
+ * the {@link AxisAngle4d} to set
+ * @return the passed in destination
+ */
+ AxisAngle4d get(AxisAngle4d dest);
+
+ /**
+ * Set the given {@link Quaterniond} to the values of this
.
+ *
+ * @param dest
+ * the {@link Quaterniond} to set
+ * @return the passed in destination
+ */
+ Quaterniond get(Quaterniond dest);
+
+ /**
+ * Set the given {@link Quaternionf} to the values of this
.
+ *
+ * @param dest
+ * the {@link Quaternionf} to set
+ * @return the passed in destination
+ */
+ Quaternionf get(Quaternionf dest);
+
+ /**
+ * Multiply this quaternion by q
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param q
+ * the quaternion to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond mul(Quaterniondc q, Quaterniond dest);
+
+ /**
+ * Multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond mul(double qx, double qy, double qz, double qw, Quaterniond dest);
+
+ /**
+ * Pre-multiply this quaternion by q
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param q
+ * the quaternion to pre-multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond premul(Quaterniondc q, Quaterniond dest);
+
+ /**
+ * Pre-multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond premul(double qx, double qy, double qz, double qw, Quaterniond dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3d transform(Vector3d vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3d transformInverse(Vector3d vec);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3d transformUnit(Vector3d vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3d transformInverseUnit(Vector3d vec);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPositiveX(Vector3d dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformPositiveX(Vector4d dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnitPositiveX(Vector3d dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnitPositiveX(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPositiveY(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformPositiveY(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnitPositiveY(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnitPositiveY(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPositiveZ(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformPositiveZ(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnitPositiveZ(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnitPositiveZ(Vector4d dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transform(Vector4d vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transformInverse(Vector4d vec);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverse(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverse(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transform(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverse(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transform(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverse(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transform(Vector3f vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transformInverse(Vector3f vec);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transformUnit(Vector4d vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transformInverseUnit(Vector4d vec);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnit(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverseUnit(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnit(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverseUnit(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnit(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverseUnit(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnit(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverseUnit(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transformUnit(Vector3f vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transformInverseUnit(Vector3f vec);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPositiveX(Vector3f dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformPositiveX(Vector4f dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnitPositiveX(Vector3f dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnitPositiveX(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPositiveY(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformPositiveY(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnitPositiveY(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnitPositiveY(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPositiveZ(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformPositiveZ(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnitPositiveZ(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnitPositiveZ(Vector4f dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transform(Vector4f vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transformInverse(Vector4f vec);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverse(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(double x, double y, double z, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverse(double x, double y, double z, Vector3f dest);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transform(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverse(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transform(double x, double y, double z, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverse(double x, double y, double z, Vector4f dest);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transformUnit(Vector4f vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transformInverseUnit(Vector4f vec);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnit(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverseUnit(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnit(double x, double y, double z, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverseUnit(double x, double y, double z, Vector3f dest);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnit(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverseUnit(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnit(double x, double y, double z, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverseUnit(double x, double y, double z, Vector4f dest);
+
+ /**
+ * Invert this quaternion and store the {@link #normalize(Quaterniond) normalized} result in dest
.
+ *
+ * If this quaternion is already normalized, then {@link #conjugate(Quaterniond)} should be used instead.
+ *
+ * @see #conjugate(Quaterniond)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond invert(Quaterniond dest);
+
+ /**
+ * Divide this
quaternion by b
and store the result in dest
.
+ *
+ * The division expressed using the inverse is performed in the following way:
+ *
+ * dest = this * b^-1
, where b^-1
is the inverse of b
.
+ *
+ * @param b
+ * the {@link Quaterniondc} to divide this by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond div(Quaterniondc b, Quaterniond dest);
+
+ /**
+ * Conjugate this quaternion and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond conjugate(Quaterniond dest);
+
+ /**
+ * Return the square of the length of this quaternion.
+ *
+ * @return the length
+ */
+ double lengthSquared();
+
+ /**
+ * Interpolate between this
{@link #normalize(Quaterniond) unit} quaternion and the specified
+ * target
{@link #normalize(Quaterniond) unit} quaternion using spherical linear interpolation using the specified interpolation factor alpha
,
+ * and store the result in dest
.
+ *
+ * This method resorts to non-spherical linear interpolation when the absolute dot product between this
and target
is
+ * below 1E-6
.
+ *
+ * Reference: http://fabiensanglard.net
+ *
+ * @param target
+ * the target of the interpolation, which should be reached with alpha = 1.0
+ * @param alpha
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond slerp(Quaterniondc target, double alpha, Quaterniond dest);
+
+ /**
+ * Apply scaling to this quaternion, which results in any vector transformed by the quaternion to change
+ * its length by the given factor
, and store the result in dest
.
+ *
+ * @param factor
+ * the scaling factor
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond scale(double factor, Quaterniond dest);
+
+ /**
+ * Integrate the rotation given by the angular velocity (vx, vy, vz)
around the x, y and z axis, respectively,
+ * with respect to the given elapsed time delta dt
and add the differentiate rotation to the rotation represented by this quaternion
+ * and store the result into dest
.
+ *
+ * This method pre-multiplies the rotation given by dt
and (vx, vy, vz)
by this
, so
+ * the angular velocities are always relative to the local coordinate system of the rotation represented by this
quaternion.
+ *
+ * This method is equivalent to calling: rotateLocal(dt * vx, dt * vy, dt * vz, dest)
+ *
+ * Reference: http://physicsforgames.blogspot.de/
+ *
+ * @param dt
+ * the delta time
+ * @param vx
+ * the angular velocity around the x axis
+ * @param vy
+ * the angular velocity around the y axis
+ * @param vz
+ * the angular velocity around the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond integrate(double dt, double vx, double vy, double vz, Quaterniond dest);
+
+ /**
+ * Compute a linear (non-spherical) interpolation of this
and the given quaternion q
+ * and store the result in dest
.
+ *
+ * Reference: http://fabiensanglard.net
+ *
+ * @param q
+ * the other quaternion
+ * @param factor
+ * the interpolation factor. It is between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond nlerp(Quaterniondc q, double factor, Quaterniond dest);
+
+ /**
+ * Compute linear (non-spherical) interpolations of this
and the given quaternion q
+ * iteratively and store the result in dest
.
+ *
+ * This method performs a series of small-step nlerp interpolations to avoid doing a costly spherical linear interpolation, like
+ * {@link #slerp(Quaterniondc, double, Quaterniond) slerp},
+ * by subdividing the rotation arc between this
and q
via non-spherical linear interpolations as long as
+ * the absolute dot product of this
and q
is greater than the given dotThreshold
parameter.
+ *
+ * Thanks to @theagentd
at http://www.java-gaming.org/ for providing the code.
+ *
+ * @param q
+ * the other quaternion
+ * @param alpha
+ * the interpolation factor, between 0.0 and 1.0
+ * @param dotThreshold
+ * the threshold for the dot product of this
and q
above which this method performs another iteration
+ * of a small-step linear interpolation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond nlerpIterative(Quaterniondc q, double alpha, double dotThreshold, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis, and store the result in dest
.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @see #lookAlong(double, double, double, double, double, double, Quaterniond)
+ *
+ * @param dir
+ * the direction to map to the positive Z axis
+ * @param up
+ * the vector which will be mapped to a vector parallel to the plane
+ * spanned by the given dir
and up
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond lookAlong(Vector3dc dir, Vector3dc up, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis, and store the result in dest
.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond lookAlong(double dirX, double dirY, double dirZ, double upX, double upY, double upZ, Quaterniond dest);
+
+ /**
+ * Compute the difference between this
and the other
quaternion
+ * and store the result in dest
.
+ *
+ * The difference is the rotation that has to be applied to get from
+ * this
rotation to other
. If T
is this
, Q
+ * is other
and D
is the computed difference, then the following equation holds:
+ *
+ * T * D = Q
+ *
+ * It is defined as: D = T^-1 * Q
, where T^-1
denotes the {@link #invert(Quaterniond) inverse} of T
.
+ *
+ * @param other
+ * the other quaternion
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond difference(Quaterniondc other, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
and
+ * store the result in dest
.
+ *
+ * Since there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: stackoverflow.com
+ *
+ * @param fromDirX
+ * the x-coordinate of the direction to rotate into the destination direction
+ * @param fromDirY
+ * the y-coordinate of the direction to rotate into the destination direction
+ * @param fromDirZ
+ * the z-coordinate of the direction to rotate into the destination direction
+ * @param toDirX
+ * the x-coordinate of the direction to rotate to
+ * @param toDirY
+ * the y-coordinate of the direction to rotate to
+ * @param toDirZ
+ * the z-coordinate of the direction to rotate to
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateTo(double fromDirX, double fromDirY, double fromDirZ, double toDirX, double toDirY, double toDirZ, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
and
+ * store the result in dest
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateTo(double, double, double, double, double, double, Quaterniond)
+ *
+ * @param fromDir
+ * the starting direction
+ * @param toDir
+ * the destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateTo(Vector3dc fromDir, Vector3dc toDir, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the x axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the x axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateX(double angle, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the y axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateY(double angle, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the z axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateZ(double angle, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local x axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local x axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateLocalX(double angle, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local y axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateLocalY(double angle, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local z axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateLocalZ(double angle, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles using rotation sequence XYZ
and store the result in dest
.
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateXYZ(double angleX, double angleY, double angleZ, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence ZYX
and store the result in dest
.
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateZYX(double angleZ, double angleY, double angleX, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence YXZ
and store the result in dest
.
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateYXZ(double angleY, double angleX, double angleZ, Quaterniond dest);
+
+ /**
+ * Get the euler angles in radians in rotation sequence XYZ
of this quaternion and store them in the
+ * provided parameter eulerAngles
.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * @param eulerAngles
+ * will hold the euler angles in radians
+ * @return the passed in vector
+ */
+ Vector3d getEulerAnglesXYZ(Vector3d eulerAngles);
+
+ /**
+ * Get the euler angles in radians in rotation sequence ZYX
of this quaternion and store them in the
+ * provided parameter eulerAngles
.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3d#x} field, the angle around Y in the {@link Vector3d#y}
+ * field and the angle around Z in the {@link Vector3d#z} field of the supplied {@link Vector3d} instance.
+ *
+ * @param eulerAngles
+ * will hold the euler angles in radians
+ * @return the passed in vector
+ */
+ Vector3d getEulerAnglesZYX(Vector3d eulerAngles);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axisX
+ * the x coordinate of the rotation axis
+ * @param axisY
+ * the y coordinate of the rotation axis
+ * @param axisZ
+ * the z coordinate of the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateAxis(double angle, double axisX, double axisY, double axisZ, Quaterniond dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateAxis(double, double, double, double, Quaterniond)
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axis
+ * the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotateAxis(double angle, Vector3dc axis, Quaterniond dest);
+
+ /**
+ * Obtain the direction of +X
before the rotation transformation represented by this
quaternion is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaterniond inv = new Quaterniond(this).invert();
+ * inv.transform(dir.set(1, 0, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d positiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +X
before the rotation transformation represented by this
normalized quaternion is applied.
+ * The quaternion must be {@link #normalize(Quaterniond) normalized} for this method to work.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaterniond inv = new Quaterniond(this).conjugate();
+ * inv.transform(dir.set(1, 0, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3d normalizedPositiveX(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the rotation transformation represented by this
quaternion is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaterniond inv = new Quaterniond(this).invert();
+ * inv.transform(dir.set(0, 1, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d positiveY(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Y
before the rotation transformation represented by this
normalized quaternion is applied.
+ * The quaternion must be {@link #normalize(Quaterniond) normalized} for this method to work.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaterniond inv = new Quaterniond(this).conjugate();
+ * inv.transform(dir.set(0, 1, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3d normalizedPositiveY(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Z
before the rotation transformation represented by this
quaternion is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaterniond inv = new Quaterniond(this).invert();
+ * inv.transform(dir.set(0, 0, 1));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d positiveZ(Vector3d dir);
+
+ /**
+ * Obtain the direction of +Z
before the rotation transformation represented by this
normalized quaternion is applied.
+ * The quaternion must be {@link #normalize(Quaterniond) normalized} for this method to work.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaterniond inv = new Quaterniond(this).conjugate();
+ * inv.transform(dir.set(0, 0, 1));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3d normalizedPositiveZ(Vector3d dir);
+
+ /**
+ * Conjugate this
by the given quaternion q
by computing q * this * q^-1
+ * and store the result into dest
.
+ *
+ * @param q
+ * the {@link Quaterniondc} to conjugate this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond conjugateBy(Quaterniondc q, Quaterniond dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ Compare the quaternion components of this
quaternion with the given quaternion using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param q
+ * the other quaternion
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the quaternion components are equal; false
otherwise
+ */
+ boolean equals(Quaterniondc q, double delta);
+
+ /**
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @param w
+ * the w component to compare to
+ * @return true
if all the quaternion components are equal
+ */
+ boolean equals(double x, double y, double z, double w);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Quaternionf.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaternionf.java
new file mode 100644
index 000000000..43e158686
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaternionf.java
@@ -0,0 +1,3066 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Quaternion of 4 single-precision floats which can represent rotation and uniform scaling.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ */
+public class Quaternionf implements Externalizable, Cloneable, Quaternionfc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The first component of the vector part.
+ */
+ public float x;
+ /**
+ * The second component of the vector part.
+ */
+ public float y;
+ /**
+ * The third component of the vector part.
+ */
+ public float z;
+ /**
+ * The real/scalar part of the quaternion.
+ */
+ public float w;
+
+ /**
+ * Create a new {@link Quaternionf} and initialize it with (x=0, y=0, z=0, w=1)
,
+ * where (x, y, z)
is the vector part of the quaternion and w
is the real/scalar part.
+ */
+ public Quaternionf() {
+ this.w = 1.0f;
+ }
+
+ /**
+ * Create a new {@link Quaternionf} and initialize its components to the given values.
+ *
+ * @param x
+ * the first component of the imaginary part
+ * @param y
+ * the second component of the imaginary part
+ * @param z
+ * the third component of the imaginary part
+ * @param w
+ * the real part
+ */
+ public Quaternionf(double x, double y, double z, double w) {
+ this.x = (float) x;
+ this.y = (float) y;
+ this.z = (float) z;
+ this.w = (float) w;
+ }
+
+ /**
+ * Create a new {@link Quaternionf} and initialize its components to the given values.
+ *
+ * @param x
+ * the first component of the imaginary part
+ * @param y
+ * the second component of the imaginary part
+ * @param z
+ * the third component of the imaginary part
+ * @param w
+ * the real part
+ */
+ public Quaternionf(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Quaternionf} and initialize its components to the same values as the given {@link Quaternionfc}.
+ *
+ * @param source
+ * the {@link Quaternionfc} to take the component values from
+ */
+ public Quaternionf(Quaternionfc source) {
+ set(source);
+ }
+
+ /**
+ * Create a new {@link Quaternionf} and initialize its components to the same values as the given {@link Quaterniondc}.
+ *
+ * @param source
+ * the {@link Quaterniondc} to take the component values from
+ */
+ public Quaternionf(Quaterniondc source) {
+ set(source);
+ }
+
+ /**
+ * Create a new {@link Quaternionf} which represents the rotation of the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ */
+ public Quaternionf(AxisAngle4f axisAngle) {
+ float sin = Math.sin(axisAngle.angle * 0.5f);
+ float cos = Math.cosFromSin(sin, axisAngle.angle * 0.5f);
+ x = axisAngle.x * sin;
+ y = axisAngle.y * sin;
+ z = axisAngle.z * sin;
+ w = cos;
+ }
+
+ /**
+ * Create a new {@link Quaterniond} which represents the rotation of the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ */
+ public Quaternionf(AxisAngle4d axisAngle) {
+ double sin = Math.sin(axisAngle.angle * 0.5f);
+ double cos = Math.cosFromSin(sin, axisAngle.angle * 0.5f);
+ x = (float) (axisAngle.x * sin);
+ y = (float) (axisAngle.y * sin);
+ z = (float) (axisAngle.z * sin);
+ w = (float) cos;
+ }
+
+ /**
+ * @return the first component of the vector part
+ */
+ public float x() {
+ return this.x;
+ }
+
+ /**
+ * @return the second component of the vector part
+ */
+ public float y() {
+ return this.y;
+ }
+
+ /**
+ * @return the third component of the vector part
+ */
+ public float z() {
+ return this.z;
+ }
+
+ /**
+ * @return the real/scalar part of the quaternion
+ */
+ public float w() {
+ return this.w;
+ }
+
+ /**
+ * Normalize this quaternion.
+ *
+ * @return this
+ */
+ public Quaternionf normalize() {
+ return normalize(this);
+ }
+
+ public Quaternionf normalize(Quaternionf dest) {
+ float invNorm = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ dest.x = x * invNorm;
+ dest.y = y * invNorm;
+ dest.z = z * invNorm;
+ dest.w = w * invNorm;
+ return dest;
+ }
+
+ /**
+ * Add the quaternion (x, y, z, w)
to this quaternion.
+ *
+ * @param x
+ * the x component of the vector part
+ * @param y
+ * the y component of the vector part
+ * @param z
+ * the z component of the vector part
+ * @param w
+ * the real/scalar component
+ * @return this
+ */
+ public Quaternionf add(float x, float y, float z, float w) {
+ return add(x, y, z, w, this);
+ }
+
+ public Quaternionf add(float x, float y, float z, float w, Quaternionf dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ dest.w = this.w + w;
+ return dest;
+ }
+
+ /**
+ * Add q2
to this quaternion.
+ *
+ * @param q2
+ * the quaternion to add to this
+ * @return this
+ */
+ public Quaternionf add(Quaternionfc q2) {
+ return add(q2, this);
+ }
+
+ public Quaternionf add(Quaternionfc q2, Quaternionf dest) {
+ dest.x = x + q2.x();
+ dest.y = y + q2.y();
+ dest.z = z + q2.z();
+ dest.w = w + q2.w();
+ return dest;
+ }
+
+ /**
+ * Return the dot of this quaternion and otherQuat
.
+ *
+ * @param otherQuat
+ * the other quaternion
+ * @return the dot product
+ */
+ public float dot(Quaternionf otherQuat) {
+ return this.x * otherQuat.x + this.y * otherQuat.y + this.z * otherQuat.z + this.w * otherQuat.w;
+ }
+
+ public float angle() {
+ return (float) (2.0 * Math.safeAcos(w));
+ }
+
+ public Matrix3f get(Matrix3f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix3d get(Matrix3d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4f get(Matrix4f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4d get(Matrix4d dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4x3f get(Matrix4x3f dest) {
+ return dest.set(this);
+ }
+
+ public Matrix4x3d get(Matrix4x3d dest) {
+ return dest.set(this);
+ }
+
+ public AxisAngle4f get(AxisAngle4f dest) {
+ float x = this.x;
+ float y = this.y;
+ float z = this.z;
+ float w = this.w;
+ if (w > 1.0f) {
+ float invNorm = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ x *= invNorm;
+ y *= invNorm;
+ z *= invNorm;
+ w *= invNorm;
+ }
+ dest.angle = (float) (2.0f * Math.acos(w));
+ float s = Math.sqrt(1.0f - w * w);
+ if (s < 0.001f) {
+ dest.x = x;
+ dest.y = y;
+ dest.z = z;
+ } else {
+ s = 1.0f / s;
+ dest.x = x * s;
+ dest.y = y * s;
+ dest.z = z * s;
+ }
+ return dest;
+ }
+
+ public AxisAngle4d get(AxisAngle4d dest) {
+ float x = this.x;
+ float y = this.y;
+ float z = this.z;
+ float w = this.w;
+ if (w > 1.0f) {
+ float invNorm = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ x *= invNorm;
+ y *= invNorm;
+ z *= invNorm;
+ w *= invNorm;
+ }
+ dest.angle = (float) (2.0f * Math.acos(w));
+ float s = Math.sqrt(1.0f - w * w);
+ if (s < 0.001f) {
+ dest.x = x;
+ dest.y = y;
+ dest.z = z;
+ } else {
+ s = 1.0f / s;
+ dest.x = x * s;
+ dest.y = y * s;
+ dest.z = z * s;
+ }
+ return dest;
+ }
+
+ public Quaterniond get(Quaterniond dest) {
+ return dest.set(this);
+ }
+
+ /**
+ * Set the given {@link Quaternionf} to the values of this
.
+ *
+ * @see #set(Quaternionfc)
+ *
+ * @param dest
+ * the {@link Quaternionf} to set
+ * @return the passed in destination
+ */
+ public Quaternionf get(Quaternionf dest) {
+ return dest.set(this);
+ }
+
+ public ByteBuffer getAsMatrix3f(ByteBuffer dest) {
+ MemUtil.INSTANCE.putMatrix3f(this, dest.position(), dest);
+ return dest;
+ }
+
+ public FloatBuffer getAsMatrix3f(FloatBuffer dest) {
+ MemUtil.INSTANCE.putMatrix3f(this, dest.position(), dest);
+ return dest;
+ }
+
+ public ByteBuffer getAsMatrix4f(ByteBuffer dest) {
+ MemUtil.INSTANCE.putMatrix4f(this, dest.position(), dest);
+ return dest;
+ }
+
+ public FloatBuffer getAsMatrix4f(FloatBuffer dest) {
+ MemUtil.INSTANCE.putMatrix4f(this, dest.position(), dest);
+ return dest;
+ }
+
+ public ByteBuffer getAsMatrix4x3f(ByteBuffer dest) {
+ MemUtil.INSTANCE.putMatrix4x3f(this, dest.position(), dest);
+ return dest;
+ }
+
+ public FloatBuffer getAsMatrix4x3f(FloatBuffer dest) {
+ MemUtil.INSTANCE.putMatrix4x3f(this, dest.position(), dest);
+ return dest;
+ }
+
+ /**
+ * Set this quaternion to the given values.
+ *
+ * @param x
+ * the new value of x
+ * @param y
+ * the new value of y
+ * @param z
+ * the new value of z
+ * @param w
+ * the new value of w
+ * @return this
+ */
+ public Quaternionf set(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a copy of q
.
+ *
+ * @param q
+ * the {@link Quaternionfc} to copy
+ * @return this
+ */
+ public Quaternionf set(Quaternionfc q) {
+ this.x = q.x();
+ this.y = q.y();
+ this.z = q.z();
+ this.w = q.w();
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a copy of q
.
+ *
+ * @param q
+ * the {@link Quaterniondc} to copy
+ * @return this
+ */
+ public Quaternionf set(Quaterniondc q) {
+ this.x = (float) q.x();
+ this.y = (float) q.y();
+ this.z = (float) q.z();
+ this.w = (float) q.w();
+ return this;
+ }
+
+ /**
+ * Set this quaternion to a rotation equivalent to the given {@link AxisAngle4f}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f}
+ * @return this
+ */
+ public Quaternionf set(AxisAngle4f axisAngle) {
+ return setAngleAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this quaternion to a rotation equivalent to the given {@link AxisAngle4d}.
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4d}
+ * @return this
+ */
+ public Quaternionf set(AxisAngle4d axisAngle) {
+ return setAngleAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this quaternion to a rotation equivalent to the supplied axis and
+ * angle (in radians).
+ *
+ * This method assumes that the given rotation axis (x, y, z)
is already normalized
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the normalized rotation axis
+ * @param y
+ * the y-component of the normalized rotation axis
+ * @param z
+ * the z-component of the normalized rotation axis
+ * @return this
+ */
+ public Quaternionf setAngleAxis(float angle, float x, float y, float z) {
+ float s = Math.sin(angle * 0.5f);
+ this.x = x * s;
+ this.y = y * s;
+ this.z = z * s;
+ this.w = Math.cosFromSin(s, angle * 0.5f);
+ return this;
+ }
+
+ /**
+ * Set this quaternion to a rotation equivalent to the supplied axis and
+ * angle (in radians).
+ *
+ * This method assumes that the given rotation axis (x, y, z)
is already normalized
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x-component of the normalized rotation axis
+ * @param y
+ * the y-component of the normalized rotation axis
+ * @param z
+ * the z-component of the normalized rotation axis
+ * @return this
+ */
+ public Quaternionf setAngleAxis(double angle, double x, double y, double z) {
+ double s = Math.sin(angle * 0.5f);
+ this.x = (float) (x * s);
+ this.y = (float) (y * s);
+ this.z = (float) (z * s);
+ this.w = (float) Math.cosFromSin(s, angle * 0.5f);
+ return this;
+ }
+
+ /**
+ * Set this {@link Quaternionf} to a rotation of the given angle in radians about the supplied
+ * axis, all of which are specified via the {@link AxisAngle4f}.
+ *
+ * @see #rotationAxis(float, float, float, float)
+ *
+ * @param axisAngle
+ * the {@link AxisAngle4f} giving the rotation angle in radians and the axis to rotate about
+ * @return this
+ */
+ public Quaternionf rotationAxis(AxisAngle4f axisAngle) {
+ return rotationAxis(axisAngle.angle, axisAngle.x, axisAngle.y, axisAngle.z);
+ }
+
+ /**
+ * Set this quaternion to a rotation of the given angle in radians about the supplied axis.
+ *
+ * @param angle
+ * the rotation angle in radians
+ * @param axisX
+ * the x-coordinate of the rotation axis
+ * @param axisY
+ * the y-coordinate of the rotation axis
+ * @param axisZ
+ * the z-coordinate of the rotation axis
+ * @return this
+ */
+ public Quaternionf rotationAxis(float angle, float axisX, float axisY, float axisZ) {
+ float hangle = angle / 2.0f;
+ float sinAngle = Math.sin(hangle);
+ float invVLength = Math.invsqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
+ return set(axisX * invVLength * sinAngle,
+ axisY * invVLength * sinAngle,
+ axisZ * invVLength * sinAngle,
+ Math.cosFromSin(sinAngle, hangle));
+ }
+
+ /**
+ * Set this quaternion to a rotation of the given angle in radians about the supplied axis.
+ *
+ * @see #rotationAxis(float, float, float, float)
+ *
+ * @param angle
+ * the rotation angle in radians
+ * @param axis
+ * the axis to rotate about
+ * @return this
+ */
+ public Quaternionf rotationAxis(float angle, Vector3fc axis) {
+ return rotationAxis(angle, axis.x(), axis.y(), axis.z());
+ }
+
+ /**
+ * Set this quaternion to represent a rotation of the given radians about the x axis.
+ *
+ * @param angle
+ * the angle in radians to rotate about the x axis
+ * @return this
+ */
+ public Quaternionf rotationX(float angle) {
+ float sin = Math.sin(angle * 0.5f);
+ float cos = Math.cosFromSin(sin, angle * 0.5f);
+ return set(sin, 0, 0, cos);
+ }
+
+ /**
+ * Set this quaternion to represent a rotation of the given radians about the y axis.
+ *
+ * @param angle
+ * the angle in radians to rotate about the y axis
+ * @return this
+ */
+ public Quaternionf rotationY(float angle) {
+ float sin = Math.sin(angle * 0.5f);
+ float cos = Math.cosFromSin(sin, angle * 0.5f);
+ return set(0, sin, 0, cos);
+ }
+
+ /**
+ * Set this quaternion to represent a rotation of the given radians about the z axis.
+ *
+ * @param angle
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaternionf rotationZ(float angle) {
+ float sin = Math.sin(angle * 0.5f);
+ float cos = Math.cosFromSin(sin, angle * 0.5f);
+ return set(0, 0, sin, cos);
+ }
+
+ private void setFromUnnormalized(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) {
+ float nm00 = m00, nm01 = m01, nm02 = m02;
+ float nm10 = m10, nm11 = m11, nm12 = m12;
+ float nm20 = m20, nm21 = m21, nm22 = m22;
+ float lenX = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ float lenY = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ float lenZ = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ nm00 *= lenX; nm01 *= lenX; nm02 *= lenX;
+ nm10 *= lenY; nm11 *= lenY; nm12 *= lenY;
+ nm20 *= lenZ; nm21 *= lenZ; nm22 *= lenZ;
+ setFromNormalized(nm00, nm01, nm02, nm10, nm11, nm12, nm20, nm21, nm22);
+ }
+
+ private void setFromNormalized(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) {
+ float t;
+ float tr = m00 + m11 + m22;
+ if (tr >= 0.0f) {
+ t = Math.sqrt(tr + 1.0f);
+ w = t * 0.5f;
+ t = 0.5f / t;
+ x = (m12 - m21) * t;
+ y = (m20 - m02) * t;
+ z = (m01 - m10) * t;
+ } else {
+ if (m00 >= m11 && m00 >= m22) {
+ t = Math.sqrt(m00 - (m11 + m22) + 1.0f);
+ x = t * 0.5f;
+ t = 0.5f / t;
+ y = (m10 + m01) * t;
+ z = (m02 + m20) * t;
+ w = (m12 - m21) * t;
+ } else if (m11 > m22) {
+ t = Math.sqrt(m11 - (m22 + m00) + 1.0f);
+ y = t * 0.5f;
+ t = 0.5f / t;
+ z = (m21 + m12) * t;
+ x = (m10 + m01) * t;
+ w = (m20 - m02) * t;
+ } else {
+ t = Math.sqrt(m22 - (m00 + m11) + 1.0f);
+ z = t * 0.5f;
+ t = 0.5f / t;
+ x = (m02 + m20) * t;
+ y = (m21 + m12) * t;
+ w = (m01 - m10) * t;
+ }
+ }
+ }
+
+ private void setFromUnnormalized(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) {
+ double nm00 = m00, nm01 = m01, nm02 = m02;
+ double nm10 = m10, nm11 = m11, nm12 = m12;
+ double nm20 = m20, nm21 = m21, nm22 = m22;
+ double lenX = Math.invsqrt(m00 * m00 + m01 * m01 + m02 * m02);
+ double lenY = Math.invsqrt(m10 * m10 + m11 * m11 + m12 * m12);
+ double lenZ = Math.invsqrt(m20 * m20 + m21 * m21 + m22 * m22);
+ nm00 *= lenX; nm01 *= lenX; nm02 *= lenX;
+ nm10 *= lenY; nm11 *= lenY; nm12 *= lenY;
+ nm20 *= lenZ; nm21 *= lenZ; nm22 *= lenZ;
+ setFromNormalized(nm00, nm01, nm02, nm10, nm11, nm12, nm20, nm21, nm22);
+ }
+
+ private void setFromNormalized(double m00, double m01, double m02, double m10, double m11, double m12, double m20, double m21, double m22) {
+ double t;
+ double tr = m00 + m11 + m22;
+ if (tr >= 0.0) {
+ t = Math.sqrt(tr + 1.0);
+ w = (float) (t * 0.5);
+ t = 0.5 / t;
+ x = (float) ((m12 - m21) * t);
+ y = (float) ((m20 - m02) * t);
+ z = (float) ((m01 - m10) * t);
+ } else {
+ if (m00 >= m11 && m00 >= m22) {
+ t = Math.sqrt(m00 - (m11 + m22) + 1.0);
+ x = (float) (t * 0.5);
+ t = 0.5 / t;
+ y = (float) ((m10 + m01) * t);
+ z = (float) ((m02 + m20) * t);
+ w = (float) ((m12 - m21) * t);
+ } else if (m11 > m22) {
+ t = Math.sqrt(m11 - (m22 + m00) + 1.0);
+ y = (float) (t * 0.5);
+ t = 0.5 / t;
+ z = (float) ((m21 + m12) * t);
+ x = (float) ((m10 + m01) * t);
+ w = (float) ((m20 - m02) * t);
+ } else {
+ t = Math.sqrt(m22 - (m00 + m11) + 1.0);
+ z = (float) (t * 0.5);
+ t = 0.5 / t;
+ x = (float) ((m02 + m20) * t);
+ y = (float) ((m21 + m12) * t);
+ w = (float) ((m01 - m10) * t);
+ }
+ }
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromUnnormalized(Matrix4fc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromUnnormalized(Matrix4x3fc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromUnnormalized(Matrix4x3dc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromNormalized(Matrix4fc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromNormalized(Matrix4x3fc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromNormalized(Matrix4x3dc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromUnnormalized(Matrix4dc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromNormalized(Matrix4dc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromUnnormalized(Matrix3fc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromNormalized(Matrix3fc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * This method assumes that the first three columns of the upper left 3x3 submatrix are no unit vectors.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromUnnormalized(Matrix3dc mat) {
+ setFromUnnormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the rotational component of the given matrix.
+ *
+ * @param mat
+ * the matrix whose rotational component is used to set this quaternion
+ * @return this
+ */
+ public Quaternionf setFromNormalized(Matrix3dc mat) {
+ setFromNormalized(mat.m00(), mat.m01(), mat.m02(), mat.m10(), mat.m11(), mat.m12(), mat.m20(), mat.m21(), mat.m22());
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in radians).
+ *
+ * @param axis
+ * the rotation axis
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Quaternionf fromAxisAngleRad(Vector3fc axis, float angle) {
+ return fromAxisAngleRad(axis.x(), axis.y(), axis.z(), angle);
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in radians).
+ *
+ * @param axisX
+ * the x component of the rotation axis
+ * @param axisY
+ * the y component of the rotation axis
+ * @param axisZ
+ * the z component of the rotation axis
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Quaternionf fromAxisAngleRad(float axisX, float axisY, float axisZ, float angle) {
+ float hangle = angle / 2.0f;
+ float sinAngle = Math.sin(hangle);
+ float vLength = Math.sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ);
+ x = axisX / vLength * sinAngle;
+ y = axisY / vLength * sinAngle;
+ z = axisZ / vLength * sinAngle;
+ w = Math.cosFromSin(sinAngle, hangle);
+ return this;
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in degrees).
+ *
+ * @param axis
+ * the rotation axis
+ * @param angle
+ * the angle in degrees
+ * @return this
+ */
+ public Quaternionf fromAxisAngleDeg(Vector3fc axis, float angle) {
+ return fromAxisAngleRad(axis.x(), axis.y(), axis.z(), Math.toRadians(angle));
+ }
+
+ /**
+ * Set this quaternion to be a representation of the supplied axis and
+ * angle (in degrees).
+ *
+ * @param axisX
+ * the x component of the rotation axis
+ * @param axisY
+ * the y component of the rotation axis
+ * @param axisZ
+ * the z component of the rotation axis
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Quaternionf fromAxisAngleDeg(float axisX, float axisY, float axisZ, float angle) {
+ return fromAxisAngleRad(axisX, axisY, axisZ, Math.toRadians(angle));
+ }
+
+ /**
+ * Multiply this quaternion by q
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param q
+ * the quaternion to multiply this
by
+ * @return this
+ */
+ public Quaternionf mul(Quaternionfc q) {
+ return mul(q, this);
+ }
+
+ public Quaternionf mul(Quaternionfc q, Quaternionf dest) {
+ return dest.set(Math.fma(w, q.x(), Math.fma(x, q.w(), Math.fma(y, q.z(), -z * q.y()))),
+ Math.fma(w, q.y(), Math.fma(-x, q.z(), Math.fma(y, q.w(), z * q.x()))),
+ Math.fma(w, q.z(), Math.fma(x, q.y(), Math.fma(-y, q.x(), z * q.w()))),
+ Math.fma(w, q.w(), Math.fma(-x, q.x(), Math.fma(-y, q.y(), -z * q.z()))));
+ }
+
+ /**
+ * Multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @return this
+ */
+ public Quaternionf mul(float qx, float qy, float qz, float qw) {
+ return mul(qx, qy, qz, qw, this);
+ }
+
+ public Quaternionf mul(float qx, float qy, float qz, float qw, Quaternionf dest) {
+ return dest.set(Math.fma(w, qx, Math.fma(x, qw, Math.fma(y, qz, -z * qy))),
+ Math.fma(w, qy, Math.fma(-x, qz, Math.fma(y, qw, z * qx))),
+ Math.fma(w, qz, Math.fma(x, qy, Math.fma(-y, qx, z * qw))),
+ Math.fma(w, qw, Math.fma(-x, qx, Math.fma(-y, qy, -z * qz))));
+ }
+
+ /**
+ * Pre-multiply this quaternion by q
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param q
+ * the quaternion to pre-multiply this
by
+ * @return this
+ */
+ public Quaternionf premul(Quaternionfc q) {
+ return premul(q, this);
+ }
+
+ public Quaternionf premul(Quaternionfc q, Quaternionf dest) {
+ return dest.set(Math.fma(q.w(), x, Math.fma(q.x(), w, Math.fma(q.y(), z, -q.z() * y))),
+ Math.fma(q.w(), y, Math.fma(-q.x(), z, Math.fma(q.y(), w, q.z() * x))),
+ Math.fma(q.w(), z, Math.fma(q.x(), y, Math.fma(-q.y(), x, q.z() * w))),
+ Math.fma(q.w(), w, Math.fma(-q.x(), x, Math.fma(-q.y(), y, -q.z() * z))));
+ }
+
+ /**
+ * Pre-multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @return this
+ */
+ public Quaternionf premul(float qx, float qy, float qz, float qw) {
+ return premul(qx, qy, qz, qw, this);
+ }
+
+ public Quaternionf premul(float qx, float qy, float qz, float qw, Quaternionf dest) {
+ return dest.set(Math.fma(qw, x, Math.fma(qx, w, Math.fma(qy, z, -qz * y))),
+ Math.fma(qw, y, Math.fma(-qx, z, Math.fma(qy, w, qz * x))),
+ Math.fma(qw, z, Math.fma(qx, y, Math.fma(-qy, x, qz * w))),
+ Math.fma(qw, w, Math.fma(-qx, x, Math.fma(-qy, y, -qz * z))));
+ }
+
+ public Vector3f transform(Vector3f vec){
+ return transform(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformInverse(Vector3f vec){
+ return transformInverse(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformPositiveX(Vector3f dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float xz = x * z;
+ float yw = y * w;
+ dest.x = ww + xx - zz - yy;
+ dest.y = xy + zw + zw + xy;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector4f transformPositiveX(Vector4f dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float xz = x * z;
+ float yw = y * w;
+ dest.x = ww + xx - zz - yy;
+ dest.y = xy + zw + zw + xy;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector3f transformUnitPositiveX(Vector3f dest) {
+ float xy = x * y, xz = x * z, yy = y * y;
+ float yw = y * w, zz = z * z, zw = z * w;
+ dest.x = 1 - yy - zz - yy - zz;
+ dest.y = xy + zw + xy + zw;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector4f transformUnitPositiveX(Vector4f dest) {
+ float yy = y * y, zz = z * z, xy = x * y;
+ float xz = x * z, yw = y * w, zw = z * w;
+ dest.x = 1 - yy - yy - zz - zz;
+ dest.y = xy + zw + xy + zw;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector3f transformPositiveY(Vector3f dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float yz = y * z;
+ float xw = x * w;
+ dest.x = -zw + xy - zw + xy;
+ dest.y = yy - zz + ww - xx;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector4f transformPositiveY(Vector4f dest) {
+ float ww = w * w, xx = x * x, yy = y * y;
+ float zz = z * z, zw = z * w, xy = x * y;
+ float yz = y * z, xw = x * w;
+ dest.x = -zw + xy - zw + xy;
+ dest.y = yy - zz + ww - xx;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector4f transformUnitPositiveY(Vector4f dest) {
+ float xx = x * x, zz = z * z, xy = x * y;
+ float yz = y * z, xw = x * w, zw = z * w;
+ dest.x = xy - zw + xy - zw;
+ dest.y = 1 - xx - xx - zz - zz;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector3f transformUnitPositiveY(Vector3f dest) {
+ float xx = x * x, zz = z * z, xy = x * y;
+ float yz = y * z, xw = x * w, zw = z * w;
+ dest.x = xy - zw + xy - zw;
+ dest.y = 1 - xx - xx - zz - zz;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector3f transformPositiveZ(Vector3f dest) {
+ float ww = w * w, xx = x * x, yy = y * y;
+ float zz = z * z, xz = x * z, yw = y * w;
+ float yz = y * z, xw = x * w;
+ dest.x = yw + xz + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = zz - yy - xx + ww;
+ return dest;
+ }
+
+ public Vector4f transformPositiveZ(Vector4f dest) {
+ float ww = w * w, xx = x * x, yy = y * y;
+ float zz = z * z, xz = x * z, yw = y * w;
+ float yz = y * z, xw = x * w;
+ dest.x = yw + xz + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = zz - yy - xx + ww;
+ return dest;
+ }
+
+ public Vector4f transformUnitPositiveZ(Vector4f dest) {
+ float xx = x * x, yy = y * y, xz = x * z;
+ float yz = y * z, xw = x * w, yw = y * w;
+ dest.x = xz + yw + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = 1 - xx - xx - yy - yy;
+ return dest;
+ }
+
+ public Vector3f transformUnitPositiveZ(Vector3f dest) {
+ float xx = x * x, yy = y * y, xz = x * z;
+ float yz = y * z, xw = x * w, yw = y * w;
+ dest.x = xz + yw + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = 1.0f - xx - xx - yy - yy;
+ return dest;
+ }
+
+ public Vector4f transform(Vector4f vec){
+ return transform(vec, vec);
+ }
+
+ public Vector4f transformInverse(Vector4f vec){
+ return transformInverse(vec, vec);
+ }
+
+ public Vector3f transform(Vector3fc vec, Vector3f dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transformInverse(Vector3fc vec, Vector3f dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transform(float x, float y, float z, Vector3f dest) {
+ float xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ float xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ float zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3f transformInverse(float x, float y, float z, Vector3f dest) {
+ float n = 1.0f / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ float qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ float xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ float xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ float zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3f transformUnit(Vector3f vec) {
+ return transformUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformInverseUnit(Vector3f vec) {
+ return transformInverseUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3f transformUnit(Vector3fc vec, Vector3f dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transformInverseUnit(Vector3fc vec, Vector3f dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3f transformUnit(float x, float y, float z, Vector3f dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector3f transformInverseUnit(float x, float y, float z, Vector3f dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4f transform(Vector4fc vec, Vector4f dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transformInverse(Vector4fc vec, Vector4f dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transform(float x, float y, float z, Vector4f dest) {
+ float xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ float xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ float zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector4f transformInverse(float x, float y, float z, Vector4f dest) {
+ float n = 1.0f / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ float qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ float xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ float xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ float zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3d transform(Vector3d vec){
+ return transform(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector3d transformInverse(Vector3d vec){
+ return transformInverse(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector4f transformUnit(Vector4f vec) {
+ return transformUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector4f transformInverseUnit(Vector4f vec) {
+ return transformInverseUnit(vec.x, vec.y, vec.z, vec);
+ }
+
+ public Vector4f transformUnit(Vector4fc vec, Vector4f dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transformInverseUnit(Vector4fc vec, Vector4f dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4f transformUnit(float x, float y, float z, Vector4f dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4f transformInverseUnit(float x, float y, float z, Vector4f dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector3d transformPositiveX(Vector3d dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float xz = x * z;
+ float yw = y * w;
+ dest.x = ww + xx - zz - yy;
+ dest.y = xy + zw + zw + xy;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector4d transformPositiveX(Vector4d dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float xz = x * z;
+ float yw = y * w;
+ dest.x = ww + xx - zz - yy;
+ dest.y = xy + zw + zw + xy;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector3d transformUnitPositiveX(Vector3d dest) {
+ float yy = y * y;
+ float zz = z * z;
+ float xy = x * y;
+ float xz = x * z;
+ float yw = y * w;
+ float zw = z * w;
+ dest.x = 1 - yy - yy - zz - zz;
+ dest.y = xy + zw + xy + zw;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector4d transformUnitPositiveX(Vector4d dest) {
+ float yy = y * y;
+ float zz = z * z;
+ float xy = x * y;
+ float xz = x * z;
+ float yw = y * w;
+ float zw = z * w;
+ dest.x = 1 - yy - yy - zz - zz;
+ dest.y = xy + zw + xy + zw;
+ dest.z = xz - yw + xz - yw;
+ return dest;
+ }
+
+ public Vector3d transformPositiveY(Vector3d dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float yz = y * z;
+ float xw = x * w;
+ dest.x = -zw + xy - zw + xy;
+ dest.y = yy - zz + ww - xx;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector4d transformPositiveY(Vector4d dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float zw = z * w;
+ float xy = x * y;
+ float yz = y * z;
+ float xw = x * w;
+ dest.x = -zw + xy - zw + xy;
+ dest.y = yy - zz + ww - xx;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector4d transformUnitPositiveY(Vector4d dest) {
+ float xx = x * x;
+ float zz = z * z;
+ float xy = x * y;
+ float yz = y * z;
+ float xw = x * w;
+ float zw = z * w;
+ dest.x = xy - zw + xy - zw;
+ dest.y = 1 - xx - xx - zz - zz;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector3d transformUnitPositiveY(Vector3d dest) {
+ float xx = x * x;
+ float zz = z * z;
+ float xy = x * y;
+ float yz = y * z;
+ float xw = x * w;
+ float zw = z * w;
+ dest.x = xy - zw + xy - zw;
+ dest.y = 1 - xx - xx - zz - zz;
+ dest.z = yz + yz + xw + xw;
+ return dest;
+ }
+
+ public Vector3d transformPositiveZ(Vector3d dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float xz = x * z;
+ float yw = y * w;
+ float yz = y * z;
+ float xw = x * w;
+ dest.x = yw + xz + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = zz - yy - xx + ww;
+ return dest;
+ }
+
+ public Vector4d transformPositiveZ(Vector4d dest) {
+ float ww = w * w;
+ float xx = x * x;
+ float yy = y * y;
+ float zz = z * z;
+ float xz = x * z;
+ float yw = y * w;
+ float yz = y * z;
+ float xw = x * w;
+ dest.x = yw + xz + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = zz - yy - xx + ww;
+ return dest;
+ }
+
+ public Vector4d transformUnitPositiveZ(Vector4d dest) {
+ float xx = x * x;
+ float yy = y * y;
+ float xz = x * z;
+ float yz = y * z;
+ float xw = x * w;
+ float yw = y * w;
+ dest.x = xz + yw + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = 1 - xx - xx - yy - yy;
+ return dest;
+ }
+
+ public Vector3d transformUnitPositiveZ(Vector3d dest) {
+ float xx = x * x;
+ float yy = y * y;
+ float xz = x * z;
+ float yz = y * z;
+ float xw = x * w;
+ float yw = y * w;
+ dest.x = xz + yw + xz + yw;
+ dest.y = yz + yz - xw - xw;
+ dest.z = 1 - xx - xx - yy - yy;
+ return dest;
+ }
+
+ public Vector4d transform(Vector4d vec){
+ return transform(vec, vec);
+ }
+
+ public Vector4d transformInverse(Vector4d vec){
+ return transformInverse(vec, vec);
+ }
+
+ public Vector3d transform(Vector3dc vec, Vector3d dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transformInverse(Vector3dc vec, Vector3d dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transform(float x, float y, float z, Vector3d dest) {
+ return transform((double) x, (double) y, (double) z, dest);
+ }
+
+ public Vector3d transformInverse(float x, float y, float z, Vector3d dest) {
+ return transformInverse((double) x, (double) y, (double) z, dest);
+ }
+
+ public Vector3d transform(double x, double y, double z, Vector3d dest) {
+ float xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ float xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ float zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector3d transformInverse(double x, double y, double z, Vector3d dest) {
+ float n = 1.0f / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ float qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ float xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ float xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ float zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector4d transform(Vector4dc vec, Vector4d dest) {
+ return transform(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transformInverse(Vector4dc vec, Vector4d dest) {
+ return transformInverse(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transform(double x, double y, double z, Vector4d dest) {
+ float xx = this.x * this.x, yy = this.y * this.y, zz = this.z * this.z, ww = this.w * this.w;
+ float xy = this.x * this.y, xz = this.x * this.z, yz = this.y * this.z, xw = this.x * this.w;
+ float zw = this.z * this.w, yw = this.y * this.w, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy - zw) * k, y, (2 * (xz + yw) * k) * z)),
+ Math.fma(2 * (xy + zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz - xw) * k) * z)),
+ Math.fma(2 * (xz - yw) * k, x, Math.fma(2 * (yz + xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector4d transformInverse(double x, double y, double z, Vector4d dest) {
+ float n = 1.0f / Math.fma(this.x, this.x, Math.fma(this.y, this.y, Math.fma(this.z, this.z, this.w * this.w)));
+ float qx = this.x * n, qy = this.y * n, qz = this.z * n, qw = this.w * n;
+ float xx = qx * qx, yy = qy * qy, zz = qz * qz, ww = qw * qw;
+ float xy = qx * qy, xz = qx * qz, yz = qy * qz, xw = qx * qw;
+ float zw = qz * qw, yw = qy * qw, k = 1 / (xx + yy + zz + ww);
+ return dest.set(Math.fma((xx - yy - zz + ww) * k, x, Math.fma(2 * (xy + zw) * k, y, (2 * (xz - yw) * k) * z)),
+ Math.fma(2 * (xy - zw) * k, x, Math.fma((yy - xx - zz + ww) * k, y, (2 * (yz + xw) * k) * z)),
+ Math.fma(2 * (xz + yw) * k, x, Math.fma(2 * (yz - xw) * k, y, ((zz - xx - yy + ww) * k) * z)));
+ }
+
+ public Vector4d transformUnit(Vector4d vec){
+ return transformUnit(vec, vec);
+ }
+
+ public Vector4d transformInverseUnit(Vector4d vec){
+ return transformInverseUnit(vec, vec);
+ }
+
+ public Vector3d transformUnit(Vector3dc vec, Vector3d dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transformInverseUnit(Vector3dc vec, Vector3d dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector3d transformUnit(float x, float y, float z, Vector3d dest) {
+ return transformUnit((double) x, (double) y, (double) z, dest);
+ }
+
+ public Vector3d transformInverseUnit(float x, float y, float z, Vector3d dest) {
+ return transformInverseUnit((double) x, (double) y, (double) z, dest);
+ }
+
+ public Vector3d transformUnit(double x, double y, double z, Vector3d dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector3d transformInverseUnit(double x, double y, double z, Vector3d dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4d transformUnit(Vector4dc vec, Vector4d dest) {
+ return transformUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transformInverseUnit(Vector4dc vec, Vector4d dest) {
+ return transformInverseUnit(vec.x(), vec.y(), vec.z(), dest);
+ }
+
+ public Vector4d transformUnit(double x, double y, double z, Vector4d dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy - zw), y, (2 * (xz + yw)) * z)),
+ Math.fma(2 * (xy + zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz - xw)) * z)),
+ Math.fma(2 * (xz - yw), x, Math.fma(2 * (yz + xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Vector4d transformInverseUnit(double x, double y, double z, Vector4d dest) {
+ float xx = this.x * this.x, xy = this.x * this.y, xz = this.x * this.z;
+ float xw = this.x * this.w, yy = this.y * this.y, yz = this.y * this.z;
+ float yw = this.y * this.w, zz = this.z * this.z, zw = this.z * this.w;
+ return dest.set(Math.fma(Math.fma(-2, yy + zz, 1), x, Math.fma(2 * (xy + zw), y, (2 * (xz - yw)) * z)),
+ Math.fma(2 * (xy - zw), x, Math.fma(Math.fma(-2, xx + zz, 1), y, (2 * (yz + xw)) * z)),
+ Math.fma(2 * (xz + yw), x, Math.fma(2 * (yz - xw), y, Math.fma(-2, xx + yy, 1) * z)));
+ }
+
+ public Quaternionf invert(Quaternionf dest) {
+ float invNorm = 1.0f / Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ dest.x = -x * invNorm;
+ dest.y = -y * invNorm;
+ dest.z = -z * invNorm;
+ dest.w = w * invNorm;
+ return dest;
+ }
+
+ /**
+ * Invert this quaternion and {@link #normalize() normalize} it.
+ *
+ * If this quaternion is already normalized, then {@link #conjugate()} should be used instead.
+ *
+ * @see #conjugate()
+ *
+ * @return this
+ */
+ public Quaternionf invert() {
+ return invert(this);
+ }
+
+ public Quaternionf div(Quaternionfc b, Quaternionf dest) {
+ float invNorm = 1.0f / Math.fma(b.x(), b.x(), Math.fma(b.y(), b.y(), Math.fma(b.z(), b.z(), b.w() * b.w())));
+ float x = -b.x() * invNorm;
+ float y = -b.y() * invNorm;
+ float z = -b.z() * invNorm;
+ float w = b.w() * invNorm;
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Divide this
quaternion by b
.
+ *
+ * The division expressed using the inverse is performed in the following way:
+ *
+ * this = this * b^-1
, where b^-1
is the inverse of b
.
+ *
+ * @param b
+ * the {@link Quaternionf} to divide this by
+ * @return this
+ */
+ public Quaternionf div(Quaternionfc b) {
+ return div(b, this);
+ }
+
+ /**
+ * Conjugate this quaternion.
+ *
+ * @return this
+ */
+ public Quaternionf conjugate() {
+ return conjugate(this);
+ }
+
+ public Quaternionf conjugate(Quaternionf dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ dest.w = w;
+ return dest;
+ }
+
+ /**
+ * Set this quaternion to the identity.
+ *
+ * @return this
+ */
+ public Quaternionf identity() {
+ x = 0;
+ y = 0;
+ z = 0;
+ w = 1;
+ return this;
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles using rotation sequence XYZ
.
+ *
+ * This method is equivalent to calling: rotateX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaternionf rotateXYZ(float angleX, float angleY, float angleZ) {
+ return rotateXYZ(angleX, angleY, angleZ, this);
+ }
+
+ public Quaternionf rotateXYZ(float angleX, float angleY, float angleZ, Quaternionf dest) {
+ float sx = Math.sin(angleX * 0.5f);
+ float cx = Math.cosFromSin(sx, angleX * 0.5f);
+ float sy = Math.sin(angleY * 0.5f);
+ float cy = Math.cosFromSin(sy, angleY * 0.5f);
+ float sz = Math.sin(angleZ * 0.5f);
+ float cz = Math.cosFromSin(sz, angleZ * 0.5f);
+
+ float cycz = cy * cz;
+ float sysz = sy * sz;
+ float sycz = sy * cz;
+ float cysz = cy * sz;
+ float w = cx*cycz - sx*sysz;
+ float x = sx*cycz + cx*sysz;
+ float y = cx*sycz - sx*cysz;
+ float z = cx*cysz + sx*sycz;
+ // right-multiply
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence ZYX
.
+ *
+ * This method is equivalent to calling: rotateZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @return this
+ */
+ public Quaternionf rotateZYX(float angleZ, float angleY, float angleX) {
+ return rotateZYX(angleZ, angleY, angleX, this);
+ }
+
+ public Quaternionf rotateZYX(float angleZ, float angleY, float angleX, Quaternionf dest) {
+ float sx = Math.sin(angleX * 0.5f);
+ float cx = Math.cosFromSin(sx, angleX * 0.5f);
+ float sy = Math.sin(angleY * 0.5f);
+ float cy = Math.cosFromSin(sy, angleY * 0.5f);
+ float sz = Math.sin(angleZ * 0.5f);
+ float cz = Math.cosFromSin(sz, angleZ * 0.5f);
+
+ float cycz = cy * cz;
+ float sysz = sy * sz;
+ float sycz = sy * cz;
+ float cysz = cy * sz;
+ float w = cx*cycz + sx*sysz;
+ float x = sx*cycz - cx*sysz;
+ float y = cx*sycz + sx*cysz;
+ float z = cx*cysz - sx*sycz;
+ // right-multiply
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence YXZ
.
+ *
+ * This method is equivalent to calling: rotateY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaternionf rotateYXZ(float angleY, float angleX, float angleZ) {
+ return rotateYXZ(angleY, angleX, angleZ, this);
+ }
+
+ public Quaternionf rotateYXZ(float angleY, float angleX, float angleZ, Quaternionf dest) {
+ float sx = Math.sin(angleX * 0.5f);
+ float cx = Math.cosFromSin(sx, angleX * 0.5f);
+ float sy = Math.sin(angleY * 0.5f);
+ float cy = Math.cosFromSin(sy, angleY * 0.5f);
+ float sz = Math.sin(angleZ * 0.5f);
+ float cz = Math.cosFromSin(sz, angleZ * 0.5f);
+
+ float yx = cy * sx;
+ float yy = sy * cx;
+ float yz = sy * sx;
+ float yw = cy * cx;
+ float x = yx * cz + yy * sz;
+ float y = yy * cz - yx * sz;
+ float z = yw * sz - yz * cz;
+ float w = yw * cz + yz * sz;
+ // right-multiply
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ public Vector3f getEulerAnglesXYZ(Vector3f eulerAngles) {
+ eulerAngles.x = Math.atan2(x * w - y * z, 0.5f - x * x - y * y);
+ eulerAngles.y = Math.safeAsin(2.0f * (x * z + y * w));
+ eulerAngles.z = Math.atan2(z * w - x * y, 0.5f - y * y - z * z);
+ return eulerAngles;
+ }
+
+ public Vector3f getEulerAnglesZYX(Vector3f eulerAngles) {
+ eulerAngles.x = Math.atan2(y * z + w * x, 0.5f - x * x + y * y);
+ eulerAngles.y = Math.safeAsin(-2.0f * (x * z - w * y));
+ eulerAngles.z = Math.atan2(x * y + w * z, 0.5f - y * y - z * z);
+ return eulerAngles;
+ }
+
+ public float lengthSquared() {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ /**
+ * Set this quaternion from the supplied euler angles (in radians) with rotation order XYZ.
+ *
+ * This method is equivalent to calling: rotationX(angleX).rotateY(angleY).rotateZ(angleZ)
+ *
+ * Reference: this stackexchange answer
+ *
+ * @param angleX
+ * the angle in radians to rotate about x
+ * @param angleY
+ * the angle in radians to rotate about y
+ * @param angleZ
+ * the angle in radians to rotate about z
+ * @return this
+ */
+ public Quaternionf rotationXYZ(float angleX, float angleY, float angleZ) {
+ float sx = Math.sin(angleX * 0.5f);
+ float cx = Math.cosFromSin(sx, angleX * 0.5f);
+ float sy = Math.sin(angleY * 0.5f);
+ float cy = Math.cosFromSin(sy, angleY * 0.5f);
+ float sz = Math.sin(angleZ * 0.5f);
+ float cz = Math.cosFromSin(sz, angleZ * 0.5f);
+
+ float cycz = cy * cz;
+ float sysz = sy * sz;
+ float sycz = sy * cz;
+ float cysz = cy * sz;
+ w = cx*cycz - sx*sysz;
+ x = sx*cycz + cx*sysz;
+ y = cx*sycz - sx*cysz;
+ z = cx*cysz + sx*sycz;
+
+ return this;
+ }
+
+ /**
+ * Set this quaternion from the supplied euler angles (in radians) with rotation order ZYX.
+ *
+ * This method is equivalent to calling: rotationZ(angleZ).rotateY(angleY).rotateX(angleX)
+ *
+ * Reference: this stackexchange answer
+ *
+ * @param angleX
+ * the angle in radians to rotate about x
+ * @param angleY
+ * the angle in radians to rotate about y
+ * @param angleZ
+ * the angle in radians to rotate about z
+ * @return this
+ */
+ public Quaternionf rotationZYX(float angleZ, float angleY, float angleX) {
+ float sx = Math.sin(angleX * 0.5f);
+ float cx = Math.cosFromSin(sx, angleX * 0.5f);
+ float sy = Math.sin(angleY * 0.5f);
+ float cy = Math.cosFromSin(sy, angleY * 0.5f);
+ float sz = Math.sin(angleZ * 0.5f);
+ float cz = Math.cosFromSin(sz, angleZ * 0.5f);
+
+ float cycz = cy * cz;
+ float sysz = sy * sz;
+ float sycz = sy * cz;
+ float cysz = cy * sz;
+ w = cx*cycz + sx*sysz;
+ x = sx*cycz - cx*sysz;
+ y = cx*sycz + sx*cysz;
+ z = cx*cysz - sx*sycz;
+
+ return this;
+ }
+
+ /**
+ * Set this quaternion from the supplied euler angles (in radians) with rotation order YXZ.
+ *
+ * This method is equivalent to calling: rotationY(angleY).rotateX(angleX).rotateZ(angleZ)
+ *
+ * Reference: https://en.wikipedia.org
+ *
+ * @param angleY
+ * the angle in radians to rotate about y
+ * @param angleX
+ * the angle in radians to rotate about x
+ * @param angleZ
+ * the angle in radians to rotate about z
+ * @return this
+ */
+ public Quaternionf rotationYXZ(float angleY, float angleX, float angleZ) {
+ float sx = Math.sin(angleX * 0.5f);
+ float cx = Math.cosFromSin(sx, angleX * 0.5f);
+ float sy = Math.sin(angleY * 0.5f);
+ float cy = Math.cosFromSin(sy, angleY * 0.5f);
+ float sz = Math.sin(angleZ * 0.5f);
+ float cz = Math.cosFromSin(sz, angleZ * 0.5f);
+
+ float x = cy * sx;
+ float y = sy * cx;
+ float z = sy * sx;
+ float w = cy * cx;
+ this.x = x * cz + y * sz;
+ this.y = y * cz - x * sz;
+ this.z = w * sz - z * cz;
+ this.w = w * cz + z * sz;
+
+ return this;
+ }
+
+ /**
+ * Interpolate between this
{@link #normalize() unit} quaternion and the specified
+ * target
{@link #normalize() unit} quaternion using spherical linear interpolation using the specified interpolation factor alpha
.
+ *
+ * This method resorts to non-spherical linear interpolation when the absolute dot product of this
and target
is
+ * below 1E-6f
.
+ *
+ * @param target
+ * the target of the interpolation, which should be reached with alpha = 1.0
+ * @param alpha
+ * the interpolation factor, within [0..1]
+ * @return this
+ */
+ public Quaternionf slerp(Quaternionfc target, float alpha) {
+ return slerp(target, alpha, this);
+ }
+
+ public Quaternionf slerp(Quaternionfc target, float alpha, Quaternionf dest) {
+ float cosom = Math.fma(x, target.x(), Math.fma(y, target.y(), Math.fma(z, target.z(), w * target.w())));
+ float absCosom = Math.abs(cosom);
+ float scale0, scale1;
+ if (1.0f - absCosom > 1E-6f) {
+ float sinSqr = 1.0f - absCosom * absCosom;
+ float sinom = Math.invsqrt(sinSqr);
+ float omega = Math.atan2(sinSqr * sinom, absCosom);
+ scale0 = (float) (Math.sin((1.0 - alpha) * omega) * sinom);
+ scale1 = (float) (Math.sin(alpha * omega) * sinom);
+ } else {
+ scale0 = 1.0f - alpha;
+ scale1 = alpha;
+ }
+ scale1 = cosom >= 0.0f ? scale1 : -scale1;
+ dest.x = Math.fma(scale0, x, scale1 * target.x());
+ dest.y = Math.fma(scale0, y, scale1 * target.y());
+ dest.z = Math.fma(scale0, z, scale1 * target.z());
+ dest.w = Math.fma(scale0, w, scale1 * target.w());
+ return dest;
+ }
+
+ /**
+ * Interpolate between all of the quaternions given in qs
via spherical linear interpolation using the specified interpolation factors weights
,
+ * and store the result in dest
.
+ *
+ * This method will interpolate between each two successive quaternions via {@link #slerp(Quaternionfc, float)} using their relative interpolation weights.
+ *
+ * This method resorts to non-spherical linear interpolation when the absolute dot product of any two interpolated quaternions is below 1E-6f
.
+ *
+ * Reference: http://gamedev.stackexchange.com/
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Quaternionfc slerp(Quaternionf[] qs, float[] weights, Quaternionf dest) {
+ dest.set(qs[0]);
+ float w = weights[0];
+ for (int i = 1; i < qs.length; i++) {
+ float w0 = w;
+ float w1 = weights[i];
+ float rw1 = w1 / (w0 + w1);
+ w += w1;
+ dest.slerp(qs[i], rw1);
+ }
+ return dest;
+ }
+
+ /**
+ * Apply scaling to this quaternion, which results in any vector transformed by this quaternion to change
+ * its length by the given factor
.
+ *
+ * @param factor
+ * the scaling factor
+ * @return this
+ */
+ public Quaternionf scale(float factor) {
+ return scale(factor, this);
+ }
+
+ public Quaternionf scale(float factor, Quaternionf dest) {
+ float sqrt = Math.sqrt(factor);
+ dest.x = sqrt * x;
+ dest.y = sqrt * y;
+ dest.z = sqrt * z;
+ dest.w = sqrt * w;
+ return dest;
+ }
+
+ /**
+ * Set this quaternion to represent scaling, which results in a transformed vector to change
+ * its length by the given factor
.
+ *
+ * @param factor
+ * the scaling factor
+ * @return this
+ */
+ public Quaternionf scaling(float factor) {
+ float sqrt = Math.sqrt(factor);
+ this.x = 0.0f;
+ this.y = 0.0f;
+ this.z = 0.0f;
+ this.w = sqrt;
+ return this;
+ }
+
+ /**
+ * Integrate the rotation given by the angular velocity (vx, vy, vz)
around the x, y and z axis, respectively,
+ * with respect to the given elapsed time delta dt
and add the differentiate rotation to the rotation represented by this quaternion.
+ *
+ * This method pre-multiplies the rotation given by dt
and (vx, vy, vz)
by this
, so
+ * the angular velocities are always relative to the local coordinate system of the rotation represented by this
quaternion.
+ *
+ * This method is equivalent to calling: rotateLocal(dt * vx, dt * vy, dt * vz)
+ *
+ * Reference: http://physicsforgames.blogspot.de/
+ *
+ * @param dt
+ * the delta time
+ * @param vx
+ * the angular velocity around the x axis
+ * @param vy
+ * the angular velocity around the y axis
+ * @param vz
+ * the angular velocity around the z axis
+ * @return this
+ */
+ public Quaternionf integrate(float dt, float vx, float vy, float vz) {
+ return integrate(dt, vx, vy, vz, this);
+ }
+
+ public Quaternionf integrate(float dt, float vx, float vy, float vz, Quaternionf dest) {
+ float thetaX = dt * vx * 0.5f;
+ float thetaY = dt * vy * 0.5f;
+ float thetaZ = dt * vz * 0.5f;
+ float thetaMagSq = thetaX * thetaX + thetaY * thetaY + thetaZ * thetaZ;
+ float s;
+ float dqX, dqY, dqZ, dqW;
+ if (thetaMagSq * thetaMagSq / 24.0f < 1E-8f) {
+ dqW = 1.0f - thetaMagSq * 0.5f;
+ s = 1.0f - thetaMagSq / 6.0f;
+ } else {
+ float thetaMag = Math.sqrt(thetaMagSq);
+ float sin = Math.sin(thetaMag);
+ s = sin / thetaMag;
+ dqW = Math.cosFromSin(sin, thetaMag);
+ }
+ dqX = thetaX * s;
+ dqY = thetaY * s;
+ dqZ = thetaZ * s;
+ /* Pre-multiplication */
+ return dest.set(Math.fma(dqW, x, Math.fma(dqX, w, Math.fma(dqY, z, -dqZ * y))),
+ Math.fma(dqW, y, Math.fma(-dqX, z, Math.fma(dqY, w, dqZ * x))),
+ Math.fma(dqW, z, Math.fma(dqX, y, Math.fma(-dqY, x, dqZ * w))),
+ Math.fma(dqW, w, Math.fma(-dqX, x, Math.fma(-dqY, y, -dqZ * z))));
+ }
+
+ /**
+ * Compute a linear (non-spherical) interpolation of this
and the given quaternion q
+ * and store the result in this
.
+ *
+ * @param q
+ * the other quaternion
+ * @param factor
+ * the interpolation factor. It is between 0.0 and 1.0
+ * @return this
+ */
+ public Quaternionf nlerp(Quaternionfc q, float factor) {
+ return nlerp(q, factor, this);
+ }
+
+ public Quaternionf nlerp(Quaternionfc q, float factor, Quaternionf dest) {
+ float cosom = Math.fma(x, q.x(), Math.fma(y, q.y(), Math.fma(z, q.z(), w * q.w())));
+ float scale0 = 1.0f - factor;
+ float scale1 = (cosom >= 0.0f) ? factor : -factor;
+ dest.x = Math.fma(scale0, x, scale1 * q.x());
+ dest.y = Math.fma(scale0, y, scale1 * q.y());
+ dest.z = Math.fma(scale0, z, scale1 * q.z());
+ dest.w = Math.fma(scale0, w, scale1 * q.w());
+ float s = Math.invsqrt(Math.fma(dest.x, dest.x, Math.fma(dest.y, dest.y, Math.fma(dest.z, dest.z, dest.w * dest.w))));
+ dest.x *= s;
+ dest.y *= s;
+ dest.z *= s;
+ dest.w *= s;
+ return dest;
+ }
+
+ /**
+ * Interpolate between all of the quaternions given in qs
via non-spherical linear interpolation using the
+ * specified interpolation factors weights
, and store the result in dest
.
+ *
+ * This method will interpolate between each two successive quaternions via {@link #nlerp(Quaternionfc, float)}
+ * using their relative interpolation weights.
+ *
+ * Reference: http://gamedev.stackexchange.com/
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Quaternionfc nlerp(Quaternionfc[] qs, float[] weights, Quaternionf dest) {
+ dest.set(qs[0]);
+ float w = weights[0];
+ for (int i = 1; i < qs.length; i++) {
+ float w0 = w;
+ float w1 = weights[i];
+ float rw1 = w1 / (w0 + w1);
+ w += w1;
+ dest.nlerp(qs[i], rw1);
+ }
+ return dest;
+ }
+
+ public Quaternionf nlerpIterative(Quaternionfc q, float alpha, float dotThreshold, Quaternionf dest) {
+ float q1x = x, q1y = y, q1z = z, q1w = w;
+ float q2x = q.x(), q2y = q.y(), q2z = q.z(), q2w = q.w();
+ float dot = Math.fma(q1x, q2x, Math.fma(q1y, q2y, Math.fma(q1z, q2z, q1w * q2w)));
+ float absDot = Math.abs(dot);
+ if (1.0f - 1E-6f < absDot) {
+ return dest.set(this);
+ }
+ float alphaN = alpha;
+ while (absDot < dotThreshold) {
+ float scale0 = 0.5f;
+ float scale1 = dot >= 0.0f ? 0.5f : -0.5f;
+ if (alphaN < 0.5f) {
+ q2x = Math.fma(scale0, q2x, scale1 * q1x);
+ q2y = Math.fma(scale0, q2y, scale1 * q1y);
+ q2z = Math.fma(scale0, q2z, scale1 * q1z);
+ q2w = Math.fma(scale0, q2w, scale1 * q1w);
+ float s = Math.invsqrt(Math.fma(q2x, q2x, Math.fma(q2y, q2y, Math.fma(q2z, q2z, q2w * q2w))));
+ q2x *= s;
+ q2y *= s;
+ q2z *= s;
+ q2w *= s;
+ alphaN = alphaN + alphaN;
+ } else {
+ q1x = Math.fma(scale0, q1x, scale1 * q2x);
+ q1y = Math.fma(scale0, q1y, scale1 * q2y);
+ q1z = Math.fma(scale0, q1z, scale1 * q2z);
+ q1w = Math.fma(scale0, q1w, scale1 * q2w);
+ float s = Math.invsqrt(Math.fma(q1x, q1x, Math.fma(q1y, q1y, Math.fma(q1z, q1z, q1w * q1w))));
+ q1x *= s;
+ q1y *= s;
+ q1z *= s;
+ q1w *= s;
+ alphaN = alphaN + alphaN - 1.0f;
+ }
+ dot = Math.fma(q1x, q2x, Math.fma(q1y, q2y, Math.fma(q1z, q2z, q1w * q2w)));
+ absDot = Math.abs(dot);
+ }
+ float scale0 = 1.0f - alphaN;
+ float scale1 = dot >= 0.0f ? alphaN : -alphaN;
+ float resX = Math.fma(scale0, q1x, scale1 * q2x);
+ float resY = Math.fma(scale0, q1y, scale1 * q2y);
+ float resZ = Math.fma(scale0, q1z, scale1 * q2z);
+ float resW = Math.fma(scale0, q1w, scale1 * q2w);
+ float s = Math.invsqrt(Math.fma(resX, resX, Math.fma(resY, resY, Math.fma(resZ, resZ, resW * resW))));
+ dest.x = resX * s;
+ dest.y = resY * s;
+ dest.z = resZ * s;
+ dest.w = resW * s;
+ return dest;
+ }
+
+ /**
+ * Compute linear (non-spherical) interpolations of this
and the given quaternion q
+ * iteratively and store the result in this
.
+ *
+ * This method performs a series of small-step nlerp interpolations to avoid doing a costly spherical linear interpolation, like
+ * {@link #slerp(Quaternionfc, float, Quaternionf) slerp},
+ * by subdividing the rotation arc between this
and q
via non-spherical linear interpolations as long as
+ * the absolute dot product of this
and q
is greater than the given dotThreshold
parameter.
+ *
+ * Thanks to @theagentd
at http://www.java-gaming.org/ for providing the code.
+ *
+ * @param q
+ * the other quaternion
+ * @param alpha
+ * the interpolation factor, between 0.0 and 1.0
+ * @param dotThreshold
+ * the threshold for the dot product of this
and q
above which this method performs another iteration
+ * of a small-step linear interpolation
+ * @return this
+ */
+ public Quaternionf nlerpIterative(Quaternionfc q, float alpha, float dotThreshold) {
+ return nlerpIterative(q, alpha, dotThreshold, this);
+ }
+
+ /**
+ * Interpolate between all of the quaternions given in qs
via iterative non-spherical linear interpolation using the
+ * specified interpolation factors weights
, and store the result in dest
.
+ *
+ * This method will interpolate between each two successive quaternions via {@link #nlerpIterative(Quaternionfc, float, float)}
+ * using their relative interpolation weights.
+ *
+ * Reference: http://gamedev.stackexchange.com/
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param dotThreshold
+ * the threshold for the dot product of each two interpolated quaternions above which {@link #nlerpIterative(Quaternionfc, float, float)} performs another iteration
+ * of a small-step linear interpolation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public static Quaternionfc nlerpIterative(Quaternionf[] qs, float[] weights, float dotThreshold, Quaternionf dest) {
+ dest.set(qs[0]);
+ float w = weights[0];
+ for (int i = 1; i < qs.length; i++) {
+ float w0 = w;
+ float w1 = weights[i];
+ float rw1 = w1 / (w0 + w1);
+ w += w1;
+ dest.nlerpIterative(qs[i], rw1, dotThreshold);
+ }
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @see #lookAlong(float, float, float, float, float, float, Quaternionf)
+ *
+ * @param dir
+ * the direction to map to the positive Z axis
+ * @param up
+ * the vector which will be mapped to a vector parallel to the plane
+ * spanned by the given dir
and up
+ * @return this
+ */
+ public Quaternionf lookAlong(Vector3fc dir, Vector3fc up) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), this);
+ }
+
+ public Quaternionf lookAlong(Vector3fc dir, Vector3fc up, Quaternionf dest) {
+ return lookAlong(dir.x(), dir.y(), dir.z(), up.x(), up.y(), up.z(), dest);
+ }
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @see #lookAlong(float, float, float, float, float, float, Quaternionf)
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @return this
+ */
+ public Quaternionf lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ) {
+ return lookAlong(dirX, dirY, dirZ, upX, upY, upZ, this);
+ }
+
+ public Quaternionf lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Quaternionf dest) {
+ // Normalize direction
+ float invDirLength = Math.invsqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ float dirnX = -dirX * invDirLength;
+ float dirnY = -dirY * invDirLength;
+ float dirnZ = -dirZ * invDirLength;
+ // left = up x dir
+ float leftX, leftY, leftZ;
+ leftX = upY * dirnZ - upZ * dirnY;
+ leftY = upZ * dirnX - upX * dirnZ;
+ leftZ = upX * dirnY - upY * dirnX;
+ // normalize left
+ float invLeftLength = Math.invsqrt(leftX * leftX + leftY * leftY + leftZ * leftZ);
+ leftX *= invLeftLength;
+ leftY *= invLeftLength;
+ leftZ *= invLeftLength;
+ // up = direction x left
+ float upnX = dirnY * leftZ - dirnZ * leftY;
+ float upnY = dirnZ * leftX - dirnX * leftZ;
+ float upnZ = dirnX * leftY - dirnY * leftX;
+
+ /* Convert orthonormal basis vectors to quaternion */
+ float x, y, z, w;
+ double t;
+ double tr = leftX + upnY + dirnZ;
+ if (tr >= 0.0) {
+ t = Math.sqrt(tr + 1.0);
+ w = (float) (t * 0.5);
+ t = 0.5 / t;
+ x = (float) ((dirnY - upnZ) * t);
+ y = (float) ((leftZ - dirnX) * t);
+ z = (float) ((upnX - leftY) * t);
+ } else {
+ if (leftX > upnY && leftX > dirnZ) {
+ t = Math.sqrt(1.0 + leftX - upnY - dirnZ);
+ x = (float) (t * 0.5);
+ t = 0.5 / t;
+ y = (float) ((leftY + upnX) * t);
+ z = (float) ((dirnX + leftZ) * t);
+ w = (float) ((dirnY - upnZ) * t);
+ } else if (upnY > dirnZ) {
+ t = Math.sqrt(1.0 + upnY - leftX - dirnZ);
+ y = (float) (t * 0.5);
+ t = 0.5 / t;
+ x = (float) ((leftY + upnX) * t);
+ z = (float) ((upnZ + dirnY) * t);
+ w = (float) ((leftZ - dirnX) * t);
+ } else {
+ t = Math.sqrt(1.0 + dirnZ - leftX - upnY);
+ z = (float) (t * 0.5);
+ t = 0.5 / t;
+ x = (float) ((dirnX + leftZ) * t);
+ y = (float) ((upnZ + dirnY) * t);
+ w = (float) ((upnX - leftY) * t);
+ }
+ }
+ /* Multiply */
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Set this
quaternion to a rotation that rotates the fromDir
vector to point along toDir
.
+ *
+ * Since there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * Reference: stackoverflow.com
+ *
+ * @param fromDirX
+ * the x-coordinate of the direction to rotate into the destination direction
+ * @param fromDirY
+ * the y-coordinate of the direction to rotate into the destination direction
+ * @param fromDirZ
+ * the z-coordinate of the direction to rotate into the destination direction
+ * @param toDirX
+ * the x-coordinate of the direction to rotate to
+ * @param toDirY
+ * the y-coordinate of the direction to rotate to
+ * @param toDirZ
+ * the z-coordinate of the direction to rotate to
+ * @return this
+ */
+ public Quaternionf rotationTo(float fromDirX, float fromDirY, float fromDirZ, float toDirX, float toDirY, float toDirZ) {
+ float fn = Math.invsqrt(Math.fma(fromDirX, fromDirX, Math.fma(fromDirY, fromDirY, fromDirZ * fromDirZ)));
+ float tn = Math.invsqrt(Math.fma(toDirX, toDirX, Math.fma(toDirY, toDirY, toDirZ * toDirZ)));
+ float fx = fromDirX * fn, fy = fromDirY * fn, fz = fromDirZ * fn;
+ float tx = toDirX * tn, ty = toDirY * tn, tz = toDirZ * tn;
+ float dot = fx * tx + fy * ty + fz * tz;
+ float x, y, z, w;
+ if (dot < -1.0f + 1E-6f) {
+ x = fy;
+ y = -fx;
+ z = 0.0f;
+ w = 0.0f;
+ if (x * x + y * y == 0.0f) {
+ x = 0.0f;
+ y = fz;
+ z = -fy;
+ w = 0.0f;
+ }
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = 0;
+ } else {
+ float sd2 = Math.sqrt((1.0f + dot) * 2.0f);
+ float isd2 = 1.0f / sd2;
+ float cx = fy * tz - fz * ty;
+ float cy = fz * tx - fx * tz;
+ float cz = fx * ty - fy * tx;
+ x = cx * isd2;
+ y = cy * isd2;
+ z = cz * isd2;
+ w = sd2 * 0.5f;
+ float n2 = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ this.x = x * n2;
+ this.y = y * n2;
+ this.z = z * n2;
+ this.w = w * n2;
+ }
+ return this;
+ }
+
+ /**
+ * Set this
quaternion to a rotation that rotates the fromDir
vector to point along toDir
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * @see #rotationTo(float, float, float, float, float, float)
+ *
+ * @param fromDir
+ * the starting direction
+ * @param toDir
+ * the destination direction
+ * @return this
+ */
+ public Quaternionf rotationTo(Vector3fc fromDir, Vector3fc toDir) {
+ return rotationTo(fromDir.x(), fromDir.y(), fromDir.z(), toDir.x(), toDir.y(), toDir.z());
+ }
+
+ public Quaternionf rotateTo(float fromDirX, float fromDirY, float fromDirZ, float toDirX, float toDirY, float toDirZ, Quaternionf dest) {
+ float fn = Math.invsqrt(Math.fma(fromDirX, fromDirX, Math.fma(fromDirY, fromDirY, fromDirZ * fromDirZ)));
+ float tn = Math.invsqrt(Math.fma(toDirX, toDirX, Math.fma(toDirY, toDirY, toDirZ * toDirZ)));
+ float fx = fromDirX * fn, fy = fromDirY * fn, fz = fromDirZ * fn;
+ float tx = toDirX * tn, ty = toDirY * tn, tz = toDirZ * tn;
+ float dot = fx * tx + fy * ty + fz * tz;
+ float x, y, z, w;
+ if (dot < -1.0f + 1E-6f) {
+ x = fy;
+ y = -fx;
+ z = 0.0f;
+ w = 0.0f;
+ if (x * x + y * y == 0.0f) {
+ x = 0.0f;
+ y = fz;
+ z = -fy;
+ w = 0.0f;
+ }
+ } else {
+ float sd2 = Math.sqrt((1.0f + dot) * 2.0f);
+ float isd2 = 1.0f / sd2;
+ float cx = fy * tz - fz * ty;
+ float cy = fz * tx - fx * tz;
+ float cz = fx * ty - fy * tx;
+ x = cx * isd2;
+ y = cy * isd2;
+ z = cz * isd2;
+ w = sd2 * 0.5f;
+ float n2 = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ x *= n2;
+ y *= n2;
+ z *= n2;
+ w *= n2;
+ }
+ /* Multiply */
+ return dest.set(Math.fma(this.w, x, Math.fma(this.x, w, Math.fma(this.y, z, -this.z * y))),
+ Math.fma(this.w, y, Math.fma(-this.x, z, Math.fma(this.y, w, this.z * x))),
+ Math.fma(this.w, z, Math.fma(this.x, y, Math.fma(-this.y, x, this.z * w))),
+ Math.fma(this.w, w, Math.fma(-this.x, x, Math.fma(-this.y, y, -this.z * z))));
+ }
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
.
+ *
+ * Since there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateTo(float, float, float, float, float, float, Quaternionf)
+ *
+ * @param fromDirX
+ * the x-coordinate of the direction to rotate into the destination direction
+ * @param fromDirY
+ * the y-coordinate of the direction to rotate into the destination direction
+ * @param fromDirZ
+ * the z-coordinate of the direction to rotate into the destination direction
+ * @param toDirX
+ * the x-coordinate of the direction to rotate to
+ * @param toDirY
+ * the y-coordinate of the direction to rotate to
+ * @param toDirZ
+ * the z-coordinate of the direction to rotate to
+ * @return this
+ */
+ public Quaternionf rotateTo(float fromDirX, float fromDirY, float fromDirZ, float toDirX, float toDirY, float toDirZ) {
+ return rotateTo(fromDirX, fromDirY, fromDirZ, toDirX, toDirY, toDirZ, this);
+ }
+
+ public Quaternionf rotateTo(Vector3fc fromDir, Vector3fc toDir, Quaternionf dest) {
+ return rotateTo(fromDir.x(), fromDir.y(), fromDir.z(), toDir.x(), toDir.y(), toDir.z(), dest);
+ }
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateTo(float, float, float, float, float, float, Quaternionf)
+ *
+ * @param fromDir
+ * the starting direction
+ * @param toDir
+ * the destination direction
+ * @return this
+ */
+ public Quaternionf rotateTo(Vector3fc fromDir, Vector3fc toDir) {
+ return rotateTo(fromDir.x(), fromDir.y(), fromDir.z(), toDir.x(), toDir.y(), toDir.z(), this);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the x axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the x axis
+ * @return this
+ */
+ public Quaternionf rotateX(float angle) {
+ return rotateX(angle, this);
+ }
+
+ public Quaternionf rotateX(float angle, Quaternionf dest) {
+ float sin = Math.sin(angle * 0.5f);
+ float cos = Math.cosFromSin(sin, angle * 0.5f);
+ return dest.set(w * sin + x * cos,
+ y * cos + z * sin,
+ z * cos - y * sin,
+ w * cos - x * sin);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the y axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the y axis
+ * @return this
+ */
+ public Quaternionf rotateY(float angle) {
+ return rotateY(angle, this);
+ }
+
+ public Quaternionf rotateY(float angle, Quaternionf dest) {
+ float sin = Math.sin(angle * 0.5f);
+ float cos = Math.cosFromSin(sin, angle * 0.5f);
+ return dest.set(x * cos - z * sin,
+ w * sin + y * cos,
+ x * sin + z * cos,
+ w * cos - y * sin);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the z axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the z axis
+ * @return this
+ */
+ public Quaternionf rotateZ(float angle) {
+ return rotateZ(angle, this);
+ }
+
+ public Quaternionf rotateZ(float angle, Quaternionf dest) {
+ float sin = Math.sin(angle * 0.5f);
+ float cos = Math.cosFromSin(sin, angle * 0.5f);
+ return dest.set(x * cos + y * sin,
+ y * cos - x * sin,
+ w * sin + z * cos,
+ w * cos - z * sin);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local x axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local x axis
+ * @return this
+ */
+ public Quaternionf rotateLocalX(float angle) {
+ return rotateLocalX(angle, this);
+ }
+
+ public Quaternionf rotateLocalX(float angle, Quaternionf dest) {
+ float hangle = angle * 0.5f;
+ float s = Math.sin(hangle);
+ float c = Math.cosFromSin(s, hangle);
+ dest.set(c * x + s * w,
+ c * y - s * z,
+ c * z + s * y,
+ c * w - s * x);
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local y axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local y axis
+ * @return this
+ */
+ public Quaternionf rotateLocalY(float angle) {
+ return rotateLocalY(angle, this);
+ }
+
+ public Quaternionf rotateLocalY(float angle, Quaternionf dest) {
+ float hangle = angle * 0.5f;
+ float s = Math.sin(hangle);
+ float c = Math.cosFromSin(s, hangle);
+ dest.set(c * x + s * z,
+ c * y + s * w,
+ c * z - s * x,
+ c * w - s * y);
+ return dest;
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local z axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local z axis
+ * @return this
+ */
+ public Quaternionf rotateLocalZ(float angle) {
+ return rotateLocalZ(angle, this);
+ }
+
+ public Quaternionf rotateLocalZ(float angle, Quaternionf dest) {
+ float hangle = angle * 0.5f;
+ float s = Math.sin(hangle);
+ float c = Math.cosFromSin(s, hangle);
+ dest.set(c * x - s * y,
+ c * y + s * x,
+ c * z + s * w,
+ c * w - s * z);
+ return dest;
+ }
+
+ public Quaternionf rotateAxis(float angle, float axisX, float axisY, float axisZ, Quaternionf dest) {
+ float hangle = angle / 2.0f;
+ float sinAngle = Math.sin(hangle);
+ float invVLength = Math.invsqrt(Math.fma(axisX, axisX, Math.fma(axisY, axisY, axisZ * axisZ)));
+ float rx = axisX * invVLength * sinAngle;
+ float ry = axisY * invVLength * sinAngle;
+ float rz = axisZ * invVLength * sinAngle;
+ float rw = Math.cosFromSin(sinAngle, hangle);
+ return dest.set(Math.fma(this.w, rx, Math.fma(this.x, rw, Math.fma(this.y, rz, -this.z * ry))),
+ Math.fma(this.w, ry, Math.fma(-this.x, rz, Math.fma(this.y, rw, this.z * rx))),
+ Math.fma(this.w, rz, Math.fma(this.x, ry, Math.fma(-this.y, rx, this.z * rw))),
+ Math.fma(this.w, rw, Math.fma(-this.x, rx, Math.fma(-this.y, ry, -this.z * rz))));
+ }
+
+ public Quaternionf rotateAxis(float angle, Vector3fc axis, Quaternionf dest) {
+ return rotateAxis(angle, axis.x(), axis.y(), axis.z(), dest);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateAxis(float, float, float, float, Quaternionf)
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axis
+ * the rotation axis
+ * @return this
+ */
+ public Quaternionf rotateAxis(float angle, Vector3fc axis) {
+ return rotateAxis(angle, axis.x(), axis.y(), axis.z(), this);
+ }
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateAxis(float, float, float, float, Quaternionf)
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axisX
+ * the x coordinate of the rotation axis
+ * @param axisY
+ * the y coordinate of the rotation axis
+ * @param axisZ
+ * the z coordinate of the rotation axis
+ * @return this
+ */
+ public Quaternionf rotateAxis(float angle, float axisX, float axisY, float axisZ) {
+ return rotateAxis(angle, axisX, axisY, axisZ, this);
+ }
+
+ /**
+ * Return a string representation of this quaternion.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this quaternion by formatting the components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the quaternion components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + " " + Runtime.format(z, formatter) + " " + Runtime.format(w, formatter) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(x);
+ out.writeFloat(y);
+ out.writeFloat(z);
+ out.writeFloat(w);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ x = in.readFloat();
+ y = in.readFloat();
+ z = in.readFloat();
+ w = in.readFloat();
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(w);
+ result = prime * result + Float.floatToIntBits(x);
+ result = prime * result + Float.floatToIntBits(y);
+ result = prime * result + Float.floatToIntBits(z);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Quaternionf other = (Quaternionf) obj;
+ if (Float.floatToIntBits(w) != Float.floatToIntBits(other.w))
+ return false;
+ if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
+ return false;
+ if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
+ return false;
+ if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z))
+ return false;
+ return true;
+ }
+
+ /**
+ * Compute the difference between this
and the other
quaternion
+ * and store the result in this
.
+ *
+ * The difference is the rotation that has to be applied to get from
+ * this
rotation to other
. If T
is this
, Q
+ * is other
and D
is the computed difference, then the following equation holds:
+ *
+ * T * D = Q
+ *
+ * It is defined as: D = T^-1 * Q
, where T^-1
denotes the {@link #invert() inverse} of T
.
+ *
+ * @param other
+ * the other quaternion
+ * @return this
+ */
+ public Quaternionf difference(Quaternionf other) {
+ return difference(other, this);
+ }
+
+ public Quaternionf difference(Quaternionfc other, Quaternionf dest) {
+ float invNorm = 1.0f / lengthSquared();
+ float x = -this.x * invNorm;
+ float y = -this.y * invNorm;
+ float z = -this.z * invNorm;
+ float w = this.w * invNorm;
+ dest.set(Math.fma(w, other.x(), Math.fma(x, other.w(), Math.fma(y, other.z(), -z * other.y()))),
+ Math.fma(w, other.y(), Math.fma(-x, other.z(), Math.fma(y, other.w(), z * other.x()))),
+ Math.fma(w, other.z(), Math.fma(x, other.y(), Math.fma(-y, other.x(), z * other.w()))),
+ Math.fma(w, other.w(), Math.fma(-x, other.x(), Math.fma(-y, other.y(), -z * other.z()))));
+ return dest;
+ }
+
+ public Vector3f positiveX(Vector3f dir) {
+ float invNorm = 1.0f / lengthSquared();
+ float nx = -x * invNorm;
+ float ny = -y * invNorm;
+ float nz = -z * invNorm;
+ float nw = w * invNorm;
+ float dy = ny + ny;
+ float dz = nz + nz;
+ dir.x = -ny * dy - nz * dz + 1.0f;
+ dir.y = nx * dy + nw * dz;
+ dir.z = nx * dz - nw * dy;
+ return dir;
+ }
+
+ public Vector3f normalizedPositiveX(Vector3f dir) {
+ float dy = y + y;
+ float dz = z + z;
+ dir.x = -y * dy - z * dz + 1.0f;
+ dir.y = x * dy - w * dz;
+ dir.z = x * dz + w * dy;
+ return dir;
+ }
+
+ public Vector3f positiveY(Vector3f dir) {
+ float invNorm = 1.0f / lengthSquared();
+ float nx = -x * invNorm;
+ float ny = -y * invNorm;
+ float nz = -z * invNorm;
+ float nw = w * invNorm;
+ float dx = nx + nx;
+ float dy = ny + ny;
+ float dz = nz + nz;
+ dir.x = nx * dy - nw * dz;
+ dir.y = -nx * dx - nz * dz + 1.0f;
+ dir.z = ny * dz + nw * dx;
+ return dir;
+ }
+
+ public Vector3f normalizedPositiveY(Vector3f dir) {
+ float dx = x + x;
+ float dy = y + y;
+ float dz = z + z;
+ dir.x = x * dy + w * dz;
+ dir.y = -x * dx - z * dz + 1.0f;
+ dir.z = y * dz - w * dx;
+ return dir;
+ }
+
+ public Vector3f positiveZ(Vector3f dir) {
+ float invNorm = 1.0f / lengthSquared();
+ float nx = -x * invNorm;
+ float ny = -y * invNorm;
+ float nz = -z * invNorm;
+ float nw = w * invNorm;
+ float dx = nx + nx;
+ float dy = ny + ny;
+ float dz = nz + nz;
+ dir.x = nx * dz + nw * dy;
+ dir.y = ny * dz - nw * dx;
+ dir.z = -nx * dx - ny * dy + 1.0f;
+ return dir;
+ }
+
+ public Vector3f normalizedPositiveZ(Vector3f dir) {
+ float dx = x + x;
+ float dy = y + y;
+ float dz = z + z;
+ dir.x = x * dz - w * dy;
+ dir.y = y * dz + w * dx;
+ dir.z = -x * dx - y * dy + 1.0f;
+ return dir;
+ }
+
+ /**
+ * Conjugate this
by the given quaternion q
by computing q * this * q^-1
.
+ *
+ * @param q
+ * the {@link Quaternionfc} to conjugate this
by
+ * @return this
+ */
+ public Quaternionf conjugateBy(Quaternionfc q) {
+ return conjugateBy(q, this);
+ }
+
+ /**
+ * Conjugate this
by the given quaternion q
by computing q * this * q^-1
+ * and store the result into dest
.
+ *
+ * @param q
+ * the {@link Quaternionfc} to conjugate this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Quaternionf conjugateBy(Quaternionfc q, Quaternionf dest) {
+ float invNorm = 1.0f / q.lengthSquared();
+ float qix = -q.x() * invNorm, qiy = -q.y() * invNorm, qiz = -q.z() * invNorm, qiw = q.w() * invNorm;
+ float qpx = Math.fma(q.w(), x, Math.fma(q.x(), w, Math.fma(q.y(), z, -q.z() * y)));
+ float qpy = Math.fma(q.w(), y, Math.fma(-q.x(), z, Math.fma(q.y(), w, q.z() * x)));
+ float qpz = Math.fma(q.w(), z, Math.fma(q.x(), y, Math.fma(-q.y(), x, q.z() * w)));
+ float qpw = Math.fma(q.w(), w, Math.fma(-q.x(), x, Math.fma(-q.y(), y, -q.z() * z)));
+ return dest.set(Math.fma(qpw, qix, Math.fma(qpx, qiw, Math.fma(qpy, qiz, -qpz * qiy))),
+ Math.fma(qpw, qiy, Math.fma(-qpx, qiz, Math.fma(qpy, qiw, qpz * qix))),
+ Math.fma(qpw, qiz, Math.fma(qpx, qiy, Math.fma(-qpy, qix, qpz * qiw))),
+ Math.fma(qpw, qiw, Math.fma(-qpx, qix, Math.fma(-qpy, qiy, -qpz * qiz))));
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z) && Math.isFinite(w);
+ }
+
+ public boolean equals(Quaternionfc q, float delta) {
+ if (this == q)
+ return true;
+ if (q == null)
+ return false;
+ if (!(q instanceof Quaternionfc))
+ return false;
+ if (!Runtime.equals(x, q.x(), delta))
+ return false;
+ if (!Runtime.equals(y, q.y(), delta))
+ return false;
+ if (!Runtime.equals(z, q.z(), delta))
+ return false;
+ if (!Runtime.equals(w, q.w(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(float x, float y, float z, float w) {
+ if (Float.floatToIntBits(this.x) != Float.floatToIntBits(x))
+ return false;
+ if (Float.floatToIntBits(this.y) != Float.floatToIntBits(y))
+ return false;
+ if (Float.floatToIntBits(this.z) != Float.floatToIntBits(z))
+ return false;
+ if (Float.floatToIntBits(this.w) != Float.floatToIntBits(w))
+ return false;
+ return true;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/QuaternionfInterpolator.java b/src/main/java/com/jozufozu/flywheel/repack/joml/QuaternionfInterpolator.java
new file mode 100644
index 000000000..596e9c26c
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/QuaternionfInterpolator.java
@@ -0,0 +1,354 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Computes the weighted average of multiple rotations represented as {@link Quaternionf} instances.
+ *
+ * Instances of this class are not thread-safe.
+ *
+ * @author Kai Burjack
+ */
+public class QuaternionfInterpolator {
+
+ /**
+ * Performs singular value decomposition on {@link Matrix3f}.
+ *
+ * This code was adapted from http://www.public.iastate.edu/.
+ *
+ * @author Kai Burjack
+ */
+ private static class SvdDecomposition3f {
+ private final float rv1[];
+ private final float w[];
+ private final float v[];
+
+ SvdDecomposition3f() {
+ this.rv1 = new float[3];
+ this.w = new float[3];
+ this.v = new float[9];
+ }
+
+ private float SIGN(float a, float b) {
+ return ((b) >= 0.0 ? Math.abs(a) : -Math.abs(a));
+ }
+
+ void svd(float[] a, int maxIterations, Matrix3f destU, Matrix3f destV) {
+ int flag, i, its, j, jj, k, l = 0, nm = 0;
+ float c, f, h, s, x, y, z;
+ float anorm = 0.0f, g = 0.0f, scale = 0.0f;
+ /* Householder reduction to bidiagonal form */
+ for (i = 0; i < 3; i++) {
+ /* left-hand reduction */
+ l = i + 1;
+ rv1[i] = scale * g;
+ g = s = scale = 0.0f;
+ for (k = i; k < 3; k++)
+ scale += Math.abs(a[k + 3 * i]);
+ if (scale != 0.0f) {
+ for (k = i; k < 3; k++) {
+ a[k + 3 * i] = (a[k + 3 * i] / scale);
+ s += (a[k + 3 * i] * a[k + 3 * i]);
+ }
+ f = a[i + 3 * i];
+ g = -SIGN((float) Math.sqrt(s), f);
+ h = f * g - s;
+ a[i + 3 * i] = f - g;
+ if (i != 3 - 1) {
+ for (j = l; j < 3; j++) {
+ for (s = 0.0f, k = i; k < 3; k++)
+ s += a[k + 3 * i] * a[k + 3 * j];
+ f = s / h;
+ for (k = i; k < 3; k++)
+ a[k + 3 * j] += f * a[k + 3 * i];
+ }
+ }
+ for (k = i; k < 3; k++)
+ a[k + 3 * i] = a[k + 3 * i] * scale;
+ }
+ w[i] = scale * g;
+
+ /* right-hand reduction */
+ g = s = scale = 0.0f;
+ if (i < 3 && i != 3 - 1) {
+ for (k = l; k < 3; k++)
+ scale += Math.abs(a[i + 3 * k]);
+ if (scale != 0.0f) {
+ for (k = l; k < 3; k++) {
+ a[i + 3 * k] = a[i + 3 * k] / scale;
+ s += a[i + 3 * k] * a[i + 3 * k];
+ }
+ f = a[i + 3 * l];
+ g = -SIGN((float) Math.sqrt(s), f);
+ h = f * g - s;
+ a[i + 3 * l] = f - g;
+ for (k = l; k < 3; k++)
+ rv1[k] = a[i + 3 * k] / h;
+ if (i != 3 - 1) {
+ for (j = l; j < 3; j++) {
+ for (s = 0.0f, k = l; k < 3; k++)
+ s += a[j + 3 * k] * a[i + 3 * k];
+ for (k = l; k < 3; k++)
+ a[j + 3 * k] += s * rv1[k];
+ }
+ }
+ for (k = l; k < 3; k++)
+ a[i + 3 * k] = a[i + 3 * k] * scale;
+ }
+ }
+ anorm = Math.max(anorm, (Math.abs(w[i]) + Math.abs(rv1[i])));
+ }
+
+ /* accumulate the right-hand transformation */
+ for (i = 3 - 1; i >= 0; i--) {
+ if (i < 3 - 1) {
+ if (g != 0.0f) {
+ for (j = l; j < 3; j++)
+ v[j + 3 * i] = (a[i + 3 * j] / a[i + 3 * l]) / g;
+ /* double division to avoid underflow */
+ for (j = l; j < 3; j++) {
+ for (s = 0.0f, k = l; k < 3; k++)
+ s += a[i + 3 * k] * v[k + 3 * j];
+ for (k = l; k < 3; k++)
+ v[k + 3 * j] += s * v[k + 3 * i];
+ }
+ }
+ for (j = l; j < 3; j++)
+ v[i + 3 * j] = v[j + 3 * i] = 0.0f;
+ }
+ v[i + 3 * i] = 1.0f;
+ g = rv1[i];
+ l = i;
+ }
+
+ /* accumulate the left-hand transformation */
+ for (i = 3 - 1; i >= 0; i--) {
+ l = i + 1;
+ g = w[i];
+ if (i < 3 - 1)
+ for (j = l; j < 3; j++)
+ a[i + 3 * j] = 0.0f;
+ if (g != 0.0f) {
+ g = 1.0f / g;
+ if (i != 3 - 1) {
+ for (j = l; j < 3; j++) {
+ for (s = 0.0f, k = l; k < 3; k++)
+ s += a[k + 3 * i] * a[k + 3 * j];
+ f = s / a[i + 3 * i] * g;
+ for (k = i; k < 3; k++)
+ a[k + 3 * j] += f * a[k + 3 * i];
+ }
+ }
+ for (j = i; j < 3; j++)
+ a[j + 3 * i] = a[j + 3 * i] * g;
+ } else {
+ for (j = i; j < 3; j++)
+ a[j + 3 * i] = 0.0f;
+ }
+ ++a[i + 3 * i];
+ }
+
+ /* diagonalize the bidiagonal form */
+ for (k = 3 - 1; k >= 0; k--) { /* loop over singular values */
+ for (its = 0; its < maxIterations; its++) { /* loop over allowed iterations */
+ flag = 1;
+ for (l = k; l >= 0; l--) { /* test for splitting */
+ nm = l - 1;
+ if (Math.abs(rv1[l]) + anorm == anorm) {
+ flag = 0;
+ break;
+ }
+ if (Math.abs(w[nm]) + anorm == anorm)
+ break;
+ }
+ if (flag != 0) {
+ c = 0.0f;
+ s = 1.0f;
+ for (i = l; i <= k; i++) {
+ f = s * rv1[i];
+ if (Math.abs(f) + anorm != anorm) {
+ g = w[i];
+ h = PYTHAG(f, g);
+ w[i] = h;
+ h = 1.0f / h;
+ c = g * h;
+ s = (-f * h);
+ for (j = 0; j < 3; j++) {
+ y = a[j + 3 * nm];
+ z = a[j + 3 * i];
+ a[j + 3 * nm] = y * c + z * s;
+ a[j + 3 * i] = z * c - y * s;
+ }
+ }
+ }
+ }
+ z = w[k];
+ if (l == k) { /* convergence */
+ if (z < 0.0f) { /* make singular value nonnegative */
+ w[k] = -z;
+ for (j = 0; j < 3; j++)
+ v[j + 3 * k] = (-v[j + 3 * k]);
+ }
+ break;
+ }
+ if (its == maxIterations - 1) {
+ throw new RuntimeException("No convergence after " + maxIterations + " iterations");
+ }
+
+ /* shift from bottom 2 x 2 minor */
+ x = w[l];
+ nm = k - 1;
+ y = w[nm];
+ g = rv1[nm];
+ h = rv1[k];
+ f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0f * h * y);
+ g = PYTHAG(f, 1.0f);
+ f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;
+
+ /* next QR transformation */
+ c = s = 1.0f;
+ for (j = l; j <= nm; j++) {
+ i = j + 1;
+ g = rv1[i];
+ y = w[i];
+ h = s * g;
+ g = c * g;
+ z = PYTHAG(f, h);
+ rv1[j] = z;
+ c = f / z;
+ s = h / z;
+ f = x * c + g * s;
+ g = g * c - x * s;
+ h = y * s;
+ y = y * c;
+ for (jj = 0; jj < 3; jj++) {
+ x = v[jj + 3 * j];
+ z = v[jj + 3 * i];
+ v[jj + 3 * j] = x * c + z * s;
+ v[jj + 3 * i] = z * c - x * s;
+ }
+ z = PYTHAG(f, h);
+ w[j] = z;
+ if (z != 0.0f) {
+ z = 1.0f / z;
+ c = f * z;
+ s = h * z;
+ }
+ f = (c * g) + (s * y);
+ x = (c * y) - (s * g);
+ for (jj = 0; jj < 3; jj++) {
+ y = a[jj + 3 * j];
+ z = a[jj + 3 * i];
+ a[jj + 3 * j] = y * c + z * s;
+ a[jj + 3 * i] = z * c - y * s;
+ }
+ }
+ rv1[l] = 0.0f;
+ rv1[k] = f;
+ w[k] = x;
+ }
+ }
+ destU.set(a);
+ destV.set(v);
+ }
+
+ private static float PYTHAG(float a, float b) {
+ float at = Math.abs(a), bt = Math.abs(b), ct, result;
+ if (at > bt) {
+ ct = bt / at;
+ result = at * (float) Math.sqrt(1.0 + ct * ct);
+ } else if (bt > 0.0f) {
+ ct = at / bt;
+ result = bt * (float) Math.sqrt(1.0 + ct * ct);
+ } else
+ result = 0.0f;
+ return (result);
+ }
+ }
+
+ private final SvdDecomposition3f svdDecomposition3f = new SvdDecomposition3f();
+ private final float[] m = new float[9];
+ private final Matrix3f u = new Matrix3f();
+ private final Matrix3f v = new Matrix3f();
+
+ /**
+ * Compute the weighted average of all of the quaternions given in qs
using the specified interpolation factors weights
, and store the result in dest
.
+ *
+ * @param qs
+ * the quaternions to interpolate over
+ * @param weights
+ * the weights of each individual quaternion in qs
+ * @param maxSvdIterations
+ * the maximum number of iterations in the Singular Value Decomposition step used by this method
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Quaternionf computeWeightedAverage(Quaternionfc[] qs, float[] weights, int maxSvdIterations, Quaternionf dest) {
+ float m00 = 0.0f, m01 = 0.0f, m02 = 0.0f;
+ float m10 = 0.0f, m11 = 0.0f, m12 = 0.0f;
+ float m20 = 0.0f, m21 = 0.0f, m22 = 0.0f;
+ // Sum the rotation matrices of qs
+ for (int i = 0; i < qs.length; i++) {
+ Quaternionfc q = qs[i];
+ float dx = q.x() + q.x();
+ float dy = q.y() + q.y();
+ float dz = q.z() + q.z();
+ float q00 = dx * q.x();
+ float q11 = dy * q.y();
+ float q22 = dz * q.z();
+ float q01 = dx * q.y();
+ float q02 = dx * q.z();
+ float q03 = dx * q.w();
+ float q12 = dy * q.z();
+ float q13 = dy * q.w();
+ float q23 = dz * q.w();
+ m00 += weights[i] * (1.0f - q11 - q22);
+ m01 += weights[i] * (q01 + q23);
+ m02 += weights[i] * (q02 - q13);
+ m10 += weights[i] * (q01 - q23);
+ m11 += weights[i] * (1.0f - q22 - q00);
+ m12 += weights[i] * (q12 + q03);
+ m20 += weights[i] * (q02 + q13);
+ m21 += weights[i] * (q12 - q03);
+ m22 += weights[i] * (1.0f - q11 - q00);
+ }
+ m[0] = m00;
+ m[1] = m01;
+ m[2] = m02;
+ m[3] = m10;
+ m[4] = m11;
+ m[5] = m12;
+ m[6] = m20;
+ m[7] = m21;
+ m[8] = m22;
+ // Compute the Singular Value Decomposition of 'm'
+ svdDecomposition3f.svd(m, maxSvdIterations, u, v);
+ // Compute rotation matrix
+ u.mul(v.transpose());
+ // Build quaternion from it
+ return dest.setFromNormalized(u).normalize();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Quaternionfc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaternionfc.java
new file mode 100644
index 000000000..495f34dda
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Quaternionfc.java
@@ -0,0 +1,2105 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a quaternion of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Quaternionfc {
+
+ /**
+ * @return the first component of the vector part
+ */
+ float x();
+
+ /**
+ * @return the second component of the vector part
+ */
+ float y();
+
+ /**
+ * @return the third component of the vector part
+ */
+ float z();
+
+ /**
+ * @return the real/scalar part of the quaternion
+ */
+ float w();
+
+ /**
+ * Normalize this quaternion and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf normalize(Quaternionf dest);
+
+ /**
+ * Add the quaternion (x, y, z, w)
to this quaternion and store the result in dest
.
+ *
+ * @param x
+ * the x component of the vector part
+ * @param y
+ * the y component of the vector part
+ * @param z
+ * the z component of the vector part
+ * @param w
+ * the real/scalar component
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf add(float x, float y, float z, float w, Quaternionf dest);
+
+ /**
+ * Add q2
to this quaternion and store the result in dest
.
+ *
+ * @param q2
+ * the quaternion to add to this
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf add(Quaternionfc q2, Quaternionf dest);
+
+ /**
+ * Return the angle in radians represented by this normalized quaternion rotation.
+ *
+ * This quaternion must be {@link #normalize(Quaternionf) normalized}.
+ *
+ * @return the angle in radians
+ */
+ float angle();
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix3f#set(Quaternionfc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix3f get(Matrix3f dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix3d#set(Quaternionfc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix3d get(Matrix3d dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix4f#set(Quaternionfc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix4f get(Matrix4f dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix4d#set(Quaternionfc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix4d get(Matrix4d dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix4x3f#set(Quaternionfc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix4x3f get(Matrix4x3f dest);
+
+ /**
+ * Set the given destination matrix to the rotation represented by this
.
+ *
+ * @see Matrix4x3d#set(Quaternionfc)
+ *
+ * @param dest
+ * the matrix to write the rotation into
+ * @return the passed in destination
+ */
+ Matrix4x3d get(Matrix4x3d dest);
+
+ /**
+ * Set the given {@link AxisAngle4f} to represent the rotation of
+ * this
quaternion.
+ *
+ * @param dest
+ * the {@link AxisAngle4f} to set
+ * @return the passed in destination
+ */
+ AxisAngle4f get(AxisAngle4f dest);
+
+ /**
+ * Set the given {@link AxisAngle4d} to represent the rotation of
+ * this
quaternion.
+ *
+ * @param dest
+ * the {@link AxisAngle4d} to set
+ * @return the passed in destination
+ */
+ AxisAngle4d get(AxisAngle4d dest);
+
+ /**
+ * Set the given {@link Quaterniond} to the values of this
.
+ *
+ * @see Quaterniond#set(Quaternionfc)
+ *
+ * @param dest
+ * the {@link Quaterniond} to set
+ * @return the passed in destination
+ */
+ Quaterniond get(Quaterniond dest);
+
+ /**
+ * Set the given {@link Quaternionf} to the values of this
.
+ *
+ * @param dest
+ * the {@link Quaternionf} to set
+ * @return the passed in destination
+ */
+ Quaternionf get(Quaternionf dest);
+
+ /**
+ * Store the 3x3 float matrix representation of this
quaternion in column-major order into the given {@link ByteBuffer}.
+ *
+ * This is equivalent to calling: this.get(new Matrix3f()).get(dest)
+ *
+ * @param dest
+ * the destination buffer
+ * @return dest
+ */
+ ByteBuffer getAsMatrix3f(ByteBuffer dest);
+
+ /**
+ * Store the 3x3 float matrix representation of this
quaternion in column-major order into the given {@link FloatBuffer}.
+ *
+ * This is equivalent to calling: this.get(new Matrix3f()).get(dest)
+ *
+ * @param dest
+ * the destination buffer
+ * @return dest
+ */
+ FloatBuffer getAsMatrix3f(FloatBuffer dest);
+
+ /**
+ * Store the 4x4 float matrix representation of this
quaternion in column-major order into the given {@link ByteBuffer}.
+ *
+ * This is equivalent to calling: this.get(new Matrix4f()).get(dest)
+ *
+ * @param dest
+ * the destination buffer
+ * @return dest
+ */
+ ByteBuffer getAsMatrix4f(ByteBuffer dest);
+
+ /**
+ * Store the 4x4 float matrix representation of this
quaternion in column-major order into the given {@link FloatBuffer}.
+ *
+ * This is equivalent to calling: this.get(new Matrix4f()).get(dest)
+ *
+ * @param dest
+ * the destination buffer
+ * @return dest
+ */
+ FloatBuffer getAsMatrix4f(FloatBuffer dest);
+
+ /**
+ * Store the 4x3 float matrix representation of this
quaternion in column-major order into the given {@link ByteBuffer}.
+ *
+ * This is equivalent to calling: this.get(new Matrix4x3f()).get(dest)
+ *
+ * @param dest
+ * the destination buffer
+ * @return dest
+ */
+ ByteBuffer getAsMatrix4x3f(ByteBuffer dest);
+
+ /**
+ * Store the 4x3 float matrix representation of this
quaternion in column-major order into the given {@link FloatBuffer}.
+ *
+ * This is equivalent to calling: this.get(new Matrix4x3f()).get(dest)
+ *
+ * @param dest
+ * the destination buffer
+ * @return dest
+ */
+ FloatBuffer getAsMatrix4x3f(FloatBuffer dest);
+
+ /**
+ * Multiply this quaternion by q
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param q
+ * the quaternion to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf mul(Quaternionfc q, Quaternionf dest);
+
+ /**
+ * Multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given
+ * quaternion, then the resulting quaternion R
is:
+ *
+ * R = T * Q
+ *
+ * So, this method uses post-multiplication like the matrix classes, resulting in a
+ * vector to be transformed by Q
first, and then by T
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf mul(float qx, float qy, float qz, float qw, Quaternionf dest);
+
+ /**
+ * Pre-multiply this quaternion by q
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param q
+ * the quaternion to pre-multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf premul(Quaternionfc q, Quaternionf dest);
+
+ /**
+ * Pre-multiply this quaternion by the quaternion represented via (qx, qy, qz, qw)
and store the result in dest
.
+ *
+ * If T
is this
and Q
is the given quaternion, then the resulting quaternion R
is:
+ *
+ * R = Q * T
+ *
+ * So, this method uses pre-multiplication, resulting in a vector to be transformed by T
first, and then by Q
.
+ *
+ * @param qx
+ * the x component of the quaternion to multiply this
by
+ * @param qy
+ * the y component of the quaternion to multiply this
by
+ * @param qz
+ * the z component of the quaternion to multiply this
by
+ * @param qw
+ * the w component of the quaternion to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf premul(float qx, float qy, float qz, float qw, Quaternionf dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transform(Vector3f vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transformInverse(Vector3f vec);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transformUnit(Vector3f vec);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPositiveX(Vector3f dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformPositiveX(Vector4f dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnitPositiveX(Vector3f dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnitPositiveX(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPositiveY(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformPositiveY(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnitPositiveY(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnitPositiveY(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformPositiveZ(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformPositiveZ(Vector4f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnitPositiveZ(Vector3f dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnitPositiveZ(Vector4f dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transform(Vector4f vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transformInverse(Vector4f vec);
+
+ /**
+ * Transform the given vector by this quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector by the inverse of quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverse(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transform(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(float x, float y, float z, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of this quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverse(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of this quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverse(float x, float y, float z, Vector3d dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3f transformInverseUnit(Vector3f vec);
+
+ /**
+ * Transform the given vector by this unit quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnit(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverseUnit(Vector3fc vec, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformUnit(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnit(float x, float y, float z, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of this unit quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f transformInverseUnit(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of this unit quaternion
+ * and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverseUnit(float x, float y, float z, Vector3d dest);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transform(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverse(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transform(float x, float y, float z, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverse(float x, float y, float z, Vector4f dest);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnit(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transformUnit(Vector4f vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4f transformInverseUnit(Vector4f vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverseUnit(Vector4fc vec, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformUnit(float x, float y, float z, Vector4f dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f transformInverseUnit(float x, float y, float z, Vector4f dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3d transform(Vector3d vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector3d transformInverse(Vector3d vec);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPositiveX(Vector3d dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformPositiveX(Vector4d dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnitPositiveX(Vector3d dest);
+
+ /**
+ * Transform the vector (1, 0, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnitPositiveX(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPositiveY(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformPositiveY(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnitPositiveY(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 1, 0)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnitPositiveY(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformPositiveZ(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformPositiveZ(Vector4d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnitPositiveZ(Vector3d dest);
+
+ /**
+ * Transform the vector (0, 0, 1)
by this unit quaternion.
+ *
+ * Only the first three components of the given 4D vector are modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * Reference: https://de.mathworks.com/
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnitPositiveZ(Vector4d dest);
+
+ /**
+ * Transform the given vector by this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transform(Vector4d vec);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transformInverse(Vector4d vec);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverse(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transform(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverse(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transform(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector by the inverse of this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverse(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transform(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverse(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector by this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transformUnit(Vector4d vec);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and modified.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @return vec
+ */
+ Vector4d transformInverseUnit(Vector4d vec);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnit(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverseUnit(Vector3dc vec, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformUnit(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d transformInverseUnit(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Transform the given vector by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnit(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector by the inverse of this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * Only the first three components of the given 4D vector are being used and set on the destination.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param vec
+ * the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverseUnit(Vector4dc vec, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformUnit(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Transform the given vector (x, y, z)
by the inverse of
+ * this unit quaternion and store the result in dest
.
+ *
+ * This will apply the rotation described by this quaternion to the given vector.
+ *
+ * This method is only applicable when this
is a unit quaternion.
+ *
+ * @param x
+ * the x coordinate of the vector to transform
+ * @param y
+ * the y coordinate of the vector to transform
+ * @param z
+ * the z coordinate of the vector to transform
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d transformInverseUnit(double x, double y, double z, Vector4d dest);
+
+ /**
+ * Invert this quaternion and store the {@link #normalize(Quaternionf) normalized} result in dest
.
+ *
+ * If this quaternion is already normalized, then {@link #conjugate(Quaternionf)} should be used instead.
+ *
+ * @see #conjugate(Quaternionf)
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf invert(Quaternionf dest);
+
+ /**
+ * Divide this
quaternion by b
and store the result in dest
.
+ *
+ * The division expressed using the inverse is performed in the following way:
+ *
+ * dest = this * b^-1
, where b^-1
is the inverse of b
.
+ *
+ * @param b
+ * the {@link Quaternionfc} to divide this by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf div(Quaternionfc b, Quaternionf dest);
+
+ /**
+ * Conjugate this quaternion and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf conjugate(Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles using rotation sequence XYZ
and store the result in dest
.
+ *
+ * This method is equivalent to calling: rotateX(angleX, dest).rotateY(angleY).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateXYZ(float angleX, float angleY, float angleZ, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence ZYX
and store the result in dest
.
+ *
+ * This method is equivalent to calling: rotateZ(angleZ, dest).rotateY(angleY).rotateX(angleX)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateZYX(float angleZ, float angleY, float angleX, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the cartesian base unit axes,
+ * called the euler angles, using the rotation sequence YXZ
and store the result in dest
.
+ *
+ * This method is equivalent to calling: rotateY(angleY, dest).rotateX(angleX).rotateZ(angleZ)
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angleY
+ * the angle in radians to rotate about the y axis
+ * @param angleX
+ * the angle in radians to rotate about the x axis
+ * @param angleZ
+ * the angle in radians to rotate about the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateYXZ(float angleY, float angleX, float angleZ, Quaternionf dest);
+
+ /**
+ * Get the euler angles in radians in rotation sequence XYZ
of this quaternion and store them in the
+ * provided parameter eulerAngles
.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * @param eulerAngles
+ * will hold the euler angles in radians
+ * @return the passed in vector
+ */
+ Vector3f getEulerAnglesXYZ(Vector3f eulerAngles);
+
+ /**
+ * Get the euler angles in radians in rotation sequence ZYX
of this quaternion and store them in the
+ * provided parameter eulerAngles
.
+ *
+ * The Euler angles are always returned as the angle around X in the {@link Vector3f#x} field, the angle around Y in the {@link Vector3f#y}
+ * field and the angle around Z in the {@link Vector3f#z} field of the supplied {@link Vector3f} instance.
+ *
+ * @param eulerAngles
+ * will hold the euler angles in radians
+ * @return the passed in vector
+ */
+ Vector3f getEulerAnglesZYX(Vector3f eulerAngles);
+
+ /**
+ * Return the square of the length of this quaternion.
+ *
+ * @return the length
+ */
+ float lengthSquared();
+
+ /**
+ * Interpolate between this
{@link #normalize(Quaternionf) unit} quaternion and the specified
+ * target
{@link #normalize(Quaternionf) unit} quaternion using spherical linear interpolation using the specified interpolation factor alpha
,
+ * and store the result in dest
.
+ *
+ * This method resorts to non-spherical linear interpolation when the absolute dot product of this
and target
is
+ * below 1E-6f
.
+ *
+ * Reference: http://fabiensanglard.net
+ *
+ * @param target
+ * the target of the interpolation, which should be reached with alpha = 1.0
+ * @param alpha
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf slerp(Quaternionfc target, float alpha, Quaternionf dest);
+
+ /**
+ * Apply scaling to this quaternion, which results in any vector transformed by the quaternion to change
+ * its length by the given factor
, and store the result in dest
.
+ *
+ * @param factor
+ * the scaling factor
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf scale(float factor, Quaternionf dest);
+
+ /**
+ * Integrate the rotation given by the angular velocity (vx, vy, vz)
around the x, y and z axis, respectively,
+ * with respect to the given elapsed time delta dt
and add the differentiate rotation to the rotation represented by this quaternion
+ * and store the result into dest
.
+ *
+ * This method pre-multiplies the rotation given by dt
and (vx, vy, vz)
by this
, so
+ * the angular velocities are always relative to the local coordinate system of the rotation represented by this
quaternion.
+ *
+ * This method is equivalent to calling: rotateLocal(dt * vx, dt * vy, dt * vz, dest)
+ *
+ * Reference: http://physicsforgames.blogspot.de/
+ *
+ * @param dt
+ * the delta time
+ * @param vx
+ * the angular velocity around the x axis
+ * @param vy
+ * the angular velocity around the y axis
+ * @param vz
+ * the angular velocity around the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf integrate(float dt, float vx, float vy, float vz, Quaternionf dest);
+
+ /**
+ * Compute a linear (non-spherical) interpolation of this
and the given quaternion q
+ * and store the result in dest
.
+ *
+ * Reference: http://fabiensanglard.net
+ *
+ * @param q
+ * the other quaternion
+ * @param factor
+ * the interpolation factor. It is between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf nlerp(Quaternionfc q, float factor, Quaternionf dest);
+
+ /**
+ * Compute linear (non-spherical) interpolations of this
and the given quaternion q
+ * iteratively and store the result in dest
.
+ *
+ * This method performs a series of small-step nlerp interpolations to avoid doing a costly spherical linear interpolation, like
+ * {@link #slerp(Quaternionfc, float, Quaternionf) slerp},
+ * by subdividing the rotation arc between this
and q
via non-spherical linear interpolations as long as
+ * the absolute dot product of this
and q
is greater than the given dotThreshold
parameter.
+ *
+ * Thanks to @theagentd
at http://www.java-gaming.org/ for providing the code.
+ *
+ * @param q
+ * the other quaternion
+ * @param alpha
+ * the interpolation factor, between 0.0 and 1.0
+ * @param dotThreshold
+ * the threshold for the dot product of this
and q
above which this method performs another iteration
+ * of a small-step linear interpolation
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf nlerpIterative(Quaternionfc q, float alpha, float dotThreshold, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis, and store the result in dest
.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @see #lookAlong(float, float, float, float, float, float, Quaternionf)
+ *
+ * @param dir
+ * the direction to map to the positive Z axis
+ * @param up
+ * the vector which will be mapped to a vector parallel to the plane
+ * spanned by the given dir
and up
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf lookAlong(Vector3fc dir, Vector3fc up, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this quaternion that maps the given direction to the positive Z axis, and store the result in dest
.
+ *
+ * Because there are multiple possibilities for such a rotation, this method will choose the one that ensures the given up direction to remain
+ * parallel to the plane spanned by the up
and dir
vectors.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: http://answers.unity3d.com
+ *
+ * @param dirX
+ * the x-coordinate of the direction to look along
+ * @param dirY
+ * the y-coordinate of the direction to look along
+ * @param dirZ
+ * the z-coordinate of the direction to look along
+ * @param upX
+ * the x-coordinate of the up vector
+ * @param upY
+ * the y-coordinate of the up vector
+ * @param upZ
+ * the z-coordinate of the up vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf lookAlong(float dirX, float dirY, float dirZ, float upX, float upY, float upZ, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
and
+ * store the result in dest
.
+ *
+ * Since there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * Reference: stackoverflow.com
+ *
+ * @param fromDirX
+ * the x-coordinate of the direction to rotate into the destination direction
+ * @param fromDirY
+ * the y-coordinate of the direction to rotate into the destination direction
+ * @param fromDirZ
+ * the z-coordinate of the direction to rotate into the destination direction
+ * @param toDirX
+ * the x-coordinate of the direction to rotate to
+ * @param toDirY
+ * the y-coordinate of the direction to rotate to
+ * @param toDirZ
+ * the z-coordinate of the direction to rotate to
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateTo(float fromDirX, float fromDirY, float fromDirZ, float toDirX, float toDirY, float toDirZ, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
that rotates the fromDir
vector to point along toDir
and
+ * store the result in dest
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateTo(float, float, float, float, float, float, Quaternionf)
+ *
+ * @param fromDir
+ * the starting direction
+ * @param toDir
+ * the destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateTo(Vector3fc fromDir, Vector3fc toDir, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the x axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the x axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateX(float angle, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the y axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateY(float angle, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the z axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateZ(float angle, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local x axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local x axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateLocalX(float angle, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local y axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local y axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateLocalY(float angle, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the local z axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be R * Q
. So when transforming a
+ * vector v
with the new quaternion by using R * Q * v
, the
+ * rotation represented by this
will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the local z axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateLocalZ(float angle, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axisX
+ * the x coordinate of the rotation axis
+ * @param axisY
+ * the y coordinate of the rotation axis
+ * @param axisZ
+ * the z coordinate of the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateAxis(float angle, float axisX, float axisY, float axisZ, Quaternionf dest);
+
+ /**
+ * Apply a rotation to this
quaternion rotating the given radians about the specified axis
+ * and store the result in dest
.
+ *
+ * If Q
is this
quaternion and R
the quaternion representing the
+ * specified rotation, then the new quaternion will be Q * R
. So when transforming a
+ * vector v
with the new quaternion by using Q * R * v
, the
+ * rotation added by this method will be applied first!
+ *
+ * @see #rotateAxis(float, float, float, float, Quaternionf)
+ *
+ * @param angle
+ * the angle in radians to rotate about the specified axis
+ * @param axis
+ * the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotateAxis(float angle, Vector3fc axis, Quaternionf dest);
+
+ /**
+ * Compute the difference between this
and the other
quaternion
+ * and store the result in dest
.
+ *
+ * The difference is the rotation that has to be applied to get from
+ * this
rotation to other
. If T
is this
, Q
+ * is other
and D
is the computed difference, then the following equation holds:
+ *
+ * T * D = Q
+ *
+ * It is defined as: D = T^-1 * Q
, where T^-1
denotes the {@link #invert(Quaternionf) inverse} of T
.
+ *
+ * @param other
+ * the other quaternion
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf difference(Quaternionfc other, Quaternionf dest);
+
+ /**
+ * Obtain the direction of +X
before the rotation transformation represented by this
quaternion is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaternionf inv = new Quaternionf(this).invert();
+ * inv.transform(dir.set(1, 0, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f positiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +X
before the rotation transformation represented by this
normalized quaternion is applied.
+ * The quaternion must be {@link #normalize(Quaternionf) normalized} for this method to work.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaternionf inv = new Quaternionf(this).conjugate();
+ * inv.transform(dir.set(1, 0, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +X
+ * @return dir
+ */
+ Vector3f normalizedPositiveX(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the rotation transformation represented by this
quaternion is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaternionf inv = new Quaternionf(this).invert();
+ * inv.transform(dir.set(0, 1, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f positiveY(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Y
before the rotation transformation represented by this
normalized quaternion is applied.
+ * The quaternion must be {@link #normalize(Quaternionf) normalized} for this method to work.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaternionf inv = new Quaternionf(this).conjugate();
+ * inv.transform(dir.set(0, 1, 0));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Y
+ * @return dir
+ */
+ Vector3f normalizedPositiveY(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Z
before the rotation transformation represented by this
quaternion is applied.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaternionf inv = new Quaternionf(this).invert();
+ * inv.transform(dir.set(0, 0, 1));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f positiveZ(Vector3f dir);
+
+ /**
+ * Obtain the direction of +Z
before the rotation transformation represented by this
normalized quaternion is applied.
+ * The quaternion must be {@link #normalize(Quaternionf) normalized} for this method to work.
+ *
+ * This method is equivalent to the following code:
+ *
+ * Quaternionf inv = new Quaternionf(this).conjugate();
+ * inv.transform(dir.set(0, 0, 1));
+ *
+ *
+ * @param dir
+ * will hold the direction of +Z
+ * @return dir
+ */
+ Vector3f normalizedPositiveZ(Vector3f dir);
+
+ /**
+ * Conjugate this
by the given quaternion q
by computing q * this * q^-1
+ * and store the result into dest
.
+ *
+ * @param q
+ * the {@link Quaternionfc} to conjugate this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf conjugateBy(Quaternionfc q, Quaternionf dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ Compare the quaternion components of this
quaternion with the given quaternion using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param q
+ * the other quaternion
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the quaternion components are equal; false
otherwise
+ */
+ boolean equals(Quaternionfc q, float delta);
+
+ /**
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @param w
+ * the w component to compare to
+ * @return true
if all the quaternion components are equal
+ */
+ boolean equals(float x, float y, float z, float w);
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Random.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Random.java
new file mode 100644
index 000000000..4ee09ab7f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Random.java
@@ -0,0 +1,169 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Pseudo-random number generator.
+ *
+ * @author Kai Burjack
+ */
+public class Random {
+
+ /**
+ * Reference http://xoroshiro.di.unimi.it/
+ */
+ private static final class Xorshiro128 {
+ /**
+ * = 0x1p-24f
+ */
+ private static final float INT_TO_FLOAT = Float.intBitsToFloat(864026624);
+
+ /**
+ * Xorshiro128 state
+ */
+ private long _s0;
+ private long _s1;
+
+ /**
+ * SplitMix64 State
+ */
+ private long state;
+
+ Xorshiro128(long seed) {
+ this.state = seed;
+ this._s0 = nextSplitMix64();
+ this._s1 = nextSplitMix64();
+ }
+
+ private long nextSplitMix64() {
+ long z = state += 0x9e3779b97f4a7c15L;
+ z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
+ z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
+ return z ^ (z >>> 31);
+ }
+
+ /**
+ * Reference: https://github.com/roquendm/
+ *
+ * @author roquendm
+ */
+ final float nextFloat() {
+ return (nextInt() >>> 8) * INT_TO_FLOAT;
+ }
+
+ private int nextInt() {
+ long s0 = _s0;
+ long s1 = _s1;
+ long result = s0 + s1;
+ s1 ^= s0;
+ rotateLeft(s0, s1);
+ return (int) (result & 0xFFFFFFFF);
+ }
+ private static long rotl_JDK4(final long x, final int k) {
+ return (x << k) | (x >>> (64 - k));
+ }
+ private static long rotl_JDK5(final long x, final int k) {
+ return Long.rotateLeft(x, k);
+ }
+ private static long rotl(final long x, final int k) {
+ if (Runtime.HAS_Long_rotateLeft)
+ return rotl_JDK5(x, k);
+ return rotl_JDK4(x, k);
+ }
+ private void rotateLeft(long s0, long s1) {
+ _s0 = rotl(s0, 55) ^ s1 ^ (s1 << 14);
+ _s1 = rotl(s1, 36);
+ }
+
+ /**
+ * Reference: https://github.com/roquendm/
+ *
+ * @author roquendm
+ */
+ final int nextInt(int n) {
+ // See notes in nextInt. This is
+ // (on average) a better choice for
+ // 64-bit VMs.
+ long r = nextInt() >>> 1;
+ // sign doesn't matter here
+ r = (r * n) >> 31;
+ return (int) r;
+ }
+ }
+
+ private final Xorshiro128 rnd;
+
+ //8020463840 is from "Case File n_221: Kabukicho"
+ private static long seedHalf = 8020463840L;
+
+ public static long newSeed() {
+ // 3512401965023503517 is from L'Ecuyer, "Tables of Linear Congruential Generators of
+ // Different Sizes and Good Lattice Structure", 1999
+ long oldSeedHalf, newSeedHalf;
+ synchronized (Random.class) {
+ oldSeedHalf = seedHalf;
+ newSeedHalf = oldSeedHalf * 3512401965023503517L;
+ seedHalf = newSeedHalf;
+ }
+ return newSeedHalf;
+ }
+
+ /**
+ * Create a new instance of {@link Random} and initialize it with a random seed.
+ */
+ public Random() {
+ this(newSeed() ^ System.nanoTime());
+ }
+
+ /**
+ * Create a new instance of {@link Random} and initialize it with the given seed
.
+ *
+ * @param seed
+ * the seed number
+ */
+ public Random(long seed) {
+ this.rnd = new Xorshiro128(seed);
+ }
+
+ /**
+ * Generate a uniformly distributed floating-point number in the half-open range [0, 1).
+ *
+ * @return a random float in the range [0..1)
+ */
+ public float nextFloat() {
+ return rnd.nextFloat();
+ }
+
+ /**
+ * Generate a uniformly distributed integer in the half-open range [0, n).
+ *
+ * @param n
+ * the upper limit (exclusive) of the generated integer
+ * @return a random integer in the range [0..n)
+ */
+ public int nextInt(int n) {
+ return rnd.nextInt(n);
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/RayAabIntersection.java b/src/main/java/com/jozufozu/flywheel/repack/joml/RayAabIntersection.java
new file mode 100644
index 000000000..6d635cb12
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/RayAabIntersection.java
@@ -0,0 +1,399 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Kai Burjack
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * This is an implementation of the Fast Ray/Axis-Aligned Bounding Box
+ * Overlap Tests using Ray Slopes paper.
+ *
+ * It is an efficient implementation when testing many axis-aligned boxes against the same ray.
+ *
+ * This class is thread-safe and can be used in a multithreaded environment when testing many axis-aligned boxes against the same ray concurrently.
+ *
+ * @author Kai Burjack
+ */
+public class RayAabIntersection {
+ private float originX, originY, originZ;
+ private float dirX, dirY, dirZ;
+
+ /* Needed for ray slope intersection method */
+ private float c_xy, c_yx, c_zy, c_yz, c_xz, c_zx;
+ private float s_xy, s_yx, s_zy, s_yz, s_xz, s_zx;
+ private byte classification;
+
+ /**
+ * Create a new {@link RayAabIntersection} without initializing a ray.
+ *
+ * Before using the {@link #test(float, float, float, float, float, float) intersect()} method,
+ * the method {@link #set(float, float, float, float, float, float) set()} must be called in order to
+ * initialize the created RayAabIntersection instance with a ray.
+ *
+ * @see #set(float, float, float, float, float, float)
+ */
+ public RayAabIntersection() {
+ }
+
+ /**
+ * Create a new {@link RayAabIntersection} and initialize it with a ray with origin (originX, originY, originZ)
+ * and direction (dirX, dirY, dirZ)
.
+ *
+ * In order to change the direction and/or origin of the ray later, use {@link #set(float, float, float, float, float, float) set()}.
+ *
+ * @see #set(float, float, float, float, float, float)
+ *
+ * @param originX
+ * the x coordinate of the origin
+ * @param originY
+ * the y coordinate of the origin
+ * @param originZ
+ * the z coordinate of the origin
+ * @param dirX
+ * the x coordinate of the direction
+ * @param dirY
+ * the y coordinate of the direction
+ * @param dirZ
+ * the z coordinate of the direction
+ */
+ public RayAabIntersection(float originX, float originY, float originZ, float dirX, float dirY, float dirZ) {
+ set(originX, originY, originZ, dirX, dirY, dirZ);
+ }
+
+ /**
+ * Update the ray stored by this {@link RayAabIntersection} with the new origin (originX, originY, originZ)
+ * and direction (dirX, dirY, dirZ)
.
+ *
+ * @param originX
+ * the x coordinate of the ray origin
+ * @param originY
+ * the y coordinate of the ray origin
+ * @param originZ
+ * the z coordinate of the ray origin
+ * @param dirX
+ * the x coordinate of the ray direction
+ * @param dirY
+ * the y coordinate of the ray direction
+ * @param dirZ
+ * the z coordinate of the ray direction
+ */
+ public void set(float originX, float originY, float originZ, float dirX, float dirY, float dirZ) {
+ this.originX = originX;
+ this.originY = originY;
+ this.originZ = originZ;
+ this.dirX = dirX;
+ this.dirY = dirY;
+ this.dirZ = dirZ;
+ precomputeSlope();
+ }
+
+ private static int signum(float f) {
+ return (f == 0.0f || Float.isNaN(f)) ? 0 : ((1 - Float.floatToIntBits(f) >>> 31) << 1) - 1;
+ }
+
+ /**
+ * Precompute the values necessary for the ray slope algorithm.
+ */
+ private void precomputeSlope() {
+ float invDirX = 1.0f / dirX;
+ float invDirY = 1.0f / dirY;
+ float invDirZ = 1.0f / dirZ;
+ s_yx = dirX * invDirY;
+ s_xy = dirY * invDirX;
+ s_zy = dirY * invDirZ;
+ s_yz = dirZ * invDirY;
+ s_xz = dirZ * invDirX;
+ s_zx = dirX * invDirZ;
+ c_xy = originY - s_xy * originX;
+ c_yx = originX - s_yx * originY;
+ c_zy = originY - s_zy * originZ;
+ c_yz = originZ - s_yz * originY;
+ c_xz = originZ - s_xz * originX; // <- original paper had a bug here. It switched originZ/originX
+ c_zx = originX - s_zx * originZ; // <- original paper had a bug here. It switched originZ/originX
+ int sgnX = signum(dirX);
+ int sgnY = signum(dirY);
+ int sgnZ = signum(dirZ);
+ classification = (byte) ((sgnZ+1) << 4 | (sgnY+1) << 2 | (sgnX+1));
+ }
+
+ /**
+ * Test whether the ray stored in this {@link RayAabIntersection} intersect the axis-aligned box
+ * given via its minimum corner (minX, minY, minZ)
and its maximum corner (maxX, maxY, maxZ)
.
+ *
+ * This implementation uses a tableswitch to dispatch to the correct intersection method.
+ *
+ * This method is thread-safe and can be used to test many axis-aligned boxes concurrently.
+ *
+ * @param minX
+ * the x coordinate of the minimum corner
+ * @param minY
+ * the y coordinate of the minimum corner
+ * @param minZ
+ * the z coordinate of the minimum corner
+ * @param maxX
+ * the x coordinate of the maximum corner
+ * @param maxY
+ * the y coordinate of the maximum corner
+ * @param maxZ
+ * the z coordinate of the maximum corner
+ * @return true
iff the ray intersects the given axis-aligned box; false
otherwise
+ */
+ public boolean test(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ // tableswitch with dense and consecutive cases (will be a simple jump based on the switch argument)
+ switch (classification) {
+ case 0: // 0b000000: // MMM
+ return MMM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 1: // 0b000001: // OMM
+ return OMM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 2: // 0b000010: // PMM
+ return PMM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 3: // 0b000011: // not used
+ return false;
+ case 4: // 0b000100: // MOM
+ return MOM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 5: // 0b000101: // OOM
+ return OOM(minX, minY, minZ, maxX, maxY);
+ case 6: // 0b000110: // POM
+ return POM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 7: // 0b000111: // not used
+ return false;
+ case 8: // 0b001000: // MPM
+ return MPM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 9: // 0b001001: // OPM
+ return OPM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 10: // 0b001010: // PPM
+ return PPM(minX, minY, minZ, maxX, maxY, maxZ);
+ case 11: // 0b001011: // not used
+ case 12: // 0b001100: // not used
+ case 13: // 0b001101: // not used
+ case 14: // 0b001110: // not used
+ case 15: // 0b001111: // not used
+ return false;
+ case 16: // 0b010000: // MMO
+ return MMO(minX, minY, minZ, maxX, maxY, maxZ);
+ case 17: // 0b010001: // OMO
+ return OMO(minX, minY, minZ, maxX, maxZ);
+ case 18: // 0b010010: // PMO
+ return PMO(minX, minY, minZ, maxX, maxY, maxZ);
+ case 19: // 0b010011: // not used
+ return false;
+ case 20: // 0b010100: // MOO
+ return MOO(minX, minY, minZ, maxY, maxZ);
+ case 21: // 0b010101: // OOO
+ return false; // <- degenerate case
+ case 22: // 0b010110: // POO
+ return POO(minY, minZ, maxX, maxY, maxZ);
+ case 23: // 0b010111: // not used
+ return false;
+ case 24: // 0b011000: // MPO
+ return MPO(minX, minY, minZ, maxX, maxY, maxZ);
+ case 25: // 0b011001: // OPO
+ return OPO(minX, minZ, maxX, maxY, maxZ);
+ case 26: // 0b011010: // PPO
+ return PPO(minX, minY, minZ, maxX, maxY, maxZ);
+ case 27: // 0b011011: // not used
+ case 28: // 0b011100: // not used
+ case 29: // 0b011101: // not used
+ case 30: // 0b011110: // not used
+ case 31: // 0b011111: // not used
+ return false;
+ case 32: // 0b100000: // MMP
+ return MMP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 33: // 0b100001: // OMP
+ return OMP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 34: // 0b100010: // PMP
+ return PMP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 35: // 0b100011: // not used
+ return false;
+ case 36: // 0b100100: // MOP
+ return MOP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 37: // 0b100101: // OOP
+ return OOP(minX, minY, maxX, maxY, maxZ);
+ case 38: // 0b100110: // POP
+ return POP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 39: // 0b100111: // not used
+ return false;
+ case 40: // 0b101000: // MPP
+ return MPP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 41: // 0b101001: // OPP
+ return OPP(minX, minY, minZ, maxX, maxY, maxZ);
+ case 42: // 0b101010: // PPP
+ return PPP(minX, minY, minZ, maxX, maxY, maxZ);
+ default:
+ return false;
+ }
+ }
+
+ /* Intersection tests for all possible ray direction cases */
+
+ private boolean MMM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originY >= minY && originZ >= minZ
+ && s_xy * minX - maxY + c_xy <= 0.0f
+ && s_yx * minY - maxX + c_yx <= 0.0f
+ && s_zy * minZ - maxY + c_zy <= 0.0f
+ && s_yz * minY - maxZ + c_yz <= 0.0f
+ && s_xz * minX - maxZ + c_xz <= 0.0f
+ && s_zx * minZ - maxX + c_zx <= 0.0f;
+ }
+ private boolean OMM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originX <= maxX && originY >= minY && originZ >= minZ
+ && s_zy * minZ - maxY + c_zy <= 0.0f
+ && s_yz * minY - maxZ + c_yz <= 0.0f;
+ }
+ private boolean PMM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX <= maxX && originY >= minY && originZ >= minZ
+ && s_xy * maxX - maxY + c_xy <= 0.0f
+ && s_yx * minY - minX + c_yx >= 0.0f
+ && s_zy * minZ - maxY + c_zy <= 0.0f
+ && s_yz * minY - maxZ + c_yz <= 0.0f
+ && s_xz * maxX - maxZ + c_xz <= 0.0f
+ && s_zx * minZ - minX + c_zx >= 0.0f;
+ }
+ private boolean MOM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originY >= minY && originY <= maxY && originX >= minX && originZ >= minZ
+ && s_xz * minX - maxZ + c_xz <= 0.0f
+ && s_zx * minZ - maxX + c_zx <= 0.0f;
+ }
+ private boolean OOM(float minX, float minY, float minZ, float maxX, float maxY) {
+ return originZ >= minZ && originX >= minX && originX <= maxX && originY >= minY && originY <= maxY;
+ }
+ private boolean POM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originY >= minY && originY <= maxY && originX <= maxX && originZ >= minZ
+ && s_xz * maxX - maxZ + c_xz <= 0.0f
+ && s_zx * minZ - minX + c_zx >= 0.0f;
+ }
+ private boolean MPM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originY <= maxY && originZ >= minZ
+ && s_xy * minX - minY + c_xy >= 0.0f
+ && s_yx * maxY - maxX + c_yx <= 0.0f
+ && s_zy * minZ - minY + c_zy >= 0.0f
+ && s_yz * maxY - maxZ + c_yz <= 0.0f
+ && s_xz * minX - maxZ + c_xz <= 0.0f
+ && s_zx * minZ - maxX + c_zx <= 0.0f;
+ }
+ private boolean OPM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originX <= maxX && originY <= maxY && originZ >= minZ
+ && s_zy * minZ - minY + c_zy >= 0.0f
+ && s_yz * maxY - maxZ + c_yz <= 0.0f;
+ }
+ private boolean PPM(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX <= maxX && originY <= maxY && originZ >= minZ
+ && s_xy * maxX - minY + c_xy >= 0.0f
+ && s_yx * maxY - minX + c_yx >= 0.0f
+ && s_zy * minZ - minY + c_zy >= 0.0f
+ && s_yz * maxY - maxZ + c_yz <= 0.0f
+ && s_xz * maxX - maxZ + c_xz <= 0.0f
+ && s_zx * minZ - minX + c_zx >= 0.0f;
+ }
+ private boolean MMO(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originZ >= minZ && originZ <= maxZ && originX >= minX && originY >= minY
+ && s_xy * minX - maxY + c_xy <= 0.0f
+ && s_yx * minY - maxX + c_yx <= 0.0f;
+ }
+ private boolean OMO(float minX, float minY, float minZ, float maxX, float maxZ) {
+ return originY >= minY && originX >= minX && originX <= maxX && originZ >= minZ && originZ <= maxZ;
+ }
+ private boolean PMO(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originZ >= minZ && originZ <= maxZ && originX <= maxX && originY >= minY
+ && s_xy * maxX - maxY + c_xy <= 0.0f
+ && s_yx * minY - minX + c_yx >= 0.0f;
+ }
+ private boolean MOO(float minX, float minY, float minZ, float maxY, float maxZ) {
+ return originX >= minX && originY >= minY && originY <= maxY && originZ >= minZ && originZ <= maxZ;
+ }
+ private boolean POO(float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX <= maxX && originY >= minY && originY <= maxY && originZ >= minZ && originZ <= maxZ;
+ }
+ private boolean MPO(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originZ >= minZ && originZ <= maxZ && originX >= minX && originY <= maxY
+ && s_xy * minX - minY + c_xy >= 0.0f
+ && s_yx * maxY - maxX + c_yx <= 0.0f;
+ }
+ private boolean OPO(float minX, float minZ, float maxX, float maxY, float maxZ) {
+ return originY <= maxY && originX >= minX && originX <= maxX && originZ >= minZ && originZ <= maxZ;
+ }
+ private boolean PPO(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originZ >= minZ && originZ <= maxZ && originX <= maxX && originY <= maxY
+ && s_xy * maxX - minY + c_xy >= 0.0f
+ && s_yx * maxY - minX + c_yx >= 0.0f;
+ }
+ private boolean MMP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originY >= minY && originZ <= maxZ
+ && s_xy * minX - maxY + c_xy <= 0.0f
+ && s_yx * minY - maxX + c_yx <= 0.0f
+ && s_zy * maxZ - maxY + c_zy <= 0.0f
+ && s_yz * minY - minZ + c_yz >= 0.0f
+ && s_xz * minX - minZ + c_xz >= 0.0f
+ && s_zx * maxZ - maxX + c_zx <= 0.0f;
+ }
+ private boolean OMP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originX <= maxX && originY >= minY && originZ <= maxZ
+ && s_zy * maxZ - maxY + c_zy <= 0.0f
+ && s_yz * minY - minZ + c_yz >= 0.0f;
+ }
+ private boolean PMP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX <= maxX && originY >= minY && originZ <= maxZ
+ && s_xy * maxX - maxY + c_xy <= 0.0f
+ && s_yx * minY - minX + c_yx >= 0.0f
+ && s_zy * maxZ - maxY + c_zy <= 0.0f
+ && s_yz * minY - minZ + c_yz >= 0.0f
+ && s_xz * maxX - minZ + c_xz >= 0.0f
+ && s_zx * maxZ - minX + c_zx >= 0.0f;
+ }
+ private boolean MOP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originY >= minY && originY <= maxY && originX >= minX && originZ <= maxZ
+ && s_xz * minX - minZ + c_xz >= 0.0f
+ && s_zx * maxZ - maxX + c_zx <= 0.0f;
+ }
+ private boolean OOP(float minX, float minY, float maxX, float maxY, float maxZ) {
+ return originZ <= maxZ && originX >= minX && originX <= maxX && originY >= minY && originY <= maxY;
+ }
+ private boolean POP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originY >= minY && originY <= maxY && originX <= maxX && originZ <= maxZ
+ && s_xz * maxX - minZ + c_xz >= 0.0f
+ && s_zx * maxZ - minX + c_zx <= 0.0f;
+ }
+ private boolean MPP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originY <= maxY && originZ <= maxZ
+ && s_xy * minX - minY + c_xy >= 0.0f
+ && s_yx * maxY - maxX + c_yx <= 0.0f
+ && s_zy * maxZ - minY + c_zy >= 0.0f
+ && s_yz * maxY - minZ + c_yz >= 0.0f
+ && s_xz * minX - minZ + c_xz >= 0.0f
+ && s_zx * maxZ - maxX + c_zx <= 0.0f;
+ }
+ private boolean OPP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX >= minX && originX <= maxX && originY <= maxY && originZ <= maxZ
+ && s_zy * maxZ - minY + c_zy <= 0.0f
+ && s_yz * maxY - minZ + c_yz <= 0.0f;
+ }
+ private boolean PPP(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
+ return originX <= maxX && originY <= maxY && originZ <= maxZ
+ && s_xy * maxX - minY + c_xy >= 0.0f
+ && s_yx * maxY - minX + c_yx >= 0.0f
+ && s_zy * maxZ - minY + c_zy >= 0.0f
+ && s_yz * maxY - minZ + c_yz >= 0.0f
+ && s_xz * maxX - minZ + c_xz >= 0.0f
+ && s_zx * maxZ - minX + c_zx >= 0.0f;
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/RoundingMode.java b/src/main/java/com/jozufozu/flywheel/repack/joml/RoundingMode.java
new file mode 100644
index 000000000..ef1036956
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/RoundingMode.java
@@ -0,0 +1,60 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2020-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * Rounding modes.
+ *
+ * @author Kai Burjack
+ */
+public class RoundingMode {
+ private RoundingMode() {}
+ /**
+ * Discards the fractional part.
+ */
+ public static final int TRUNCATE = 0;
+ /**
+ * Round towards positive infinity.
+ */
+ public static final int CEILING = 1;
+ /**
+ * Round towards negative infinity.
+ */
+ public static final int FLOOR = 2;
+ /**
+ * Round towards the nearest neighbor. If both neighbors are equidistant, round
+ * towards the even neighbor.
+ */
+ public static final int HALF_EVEN = 3;
+ /**
+ * Round towards the nearest neighbor. If both neighbors are equidistant, round
+ * down.
+ */
+ public static final int HALF_DOWN = 4;
+ /**
+ * Round towards the nearest neighbor. If both neighbors are equidistant, round
+ * up.
+ */
+ public static final int HALF_UP = 5;
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Runtime.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Runtime.java
new file mode 100644
index 000000000..d6bd9b9d3
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Runtime.java
@@ -0,0 +1,148 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2017-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.text.NumberFormat;
+
+/**
+ * Internal class to detect features of the runtime.
+ *
+ * @author Kai Burjack
+ */
+public final class Runtime {
+
+ public static final boolean HAS_floatToRawIntBits = hasFloatToRawIntBits();
+ public static final boolean HAS_doubleToRawLongBits = hasDoubleToRawLongBits();
+ public static final boolean HAS_Long_rotateLeft = hasLongRotateLeft();
+ public static final boolean HAS_Math_fma = Options.USE_MATH_FMA && hasMathFma();
+
+ private static boolean hasMathFma() {
+ try {
+ java.lang.Math.class.getDeclaredMethod("fma", new Class[] { float.class, float.class, float.class });
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
+ private Runtime() {
+ }
+
+ private static boolean hasFloatToRawIntBits() {
+ try {
+ Float.class.getDeclaredMethod("floatToRawIntBits", new Class[] { float.class });
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
+ private static boolean hasDoubleToRawLongBits() {
+ try {
+ Double.class.getDeclaredMethod("doubleToRawLongBits", new Class[] { double.class });
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
+ private static boolean hasLongRotateLeft() {
+ try {
+ Long.class.getDeclaredMethod("rotateLeft", new Class[] { long.class, int.class });
+ return true;
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
+ public static int floatToIntBits(float flt) {
+ if (HAS_floatToRawIntBits)
+ return floatToIntBits1_3(flt);
+ return floatToIntBits1_2(flt);
+ }
+ private static int floatToIntBits1_3(float flt) {
+ return Float.floatToRawIntBits(flt);
+ }
+ private static int floatToIntBits1_2(float flt) {
+ return Float.floatToIntBits(flt);
+ }
+
+ public static long doubleToLongBits(double dbl) {
+ if (HAS_doubleToRawLongBits)
+ return doubleToLongBits1_3(dbl);
+ return doubleToLongBits1_2(dbl);
+ }
+ private static long doubleToLongBits1_3(double dbl) {
+ return Double.doubleToRawLongBits(dbl);
+ }
+ private static long doubleToLongBits1_2(double dbl) {
+ return Double.doubleToLongBits(dbl);
+ }
+
+ public static String formatNumbers(String str) {
+ StringBuffer res = new StringBuffer();
+ int eIndex = Integer.MIN_VALUE;
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (c == 'E') {
+ eIndex = i;
+ } else if (c == ' ' && eIndex == i - 1) {
+ // workaround Java 1.4 DecimalFormat bug
+ res.append('+');
+ continue;
+ } else if (Character.isDigit(c) && eIndex == i - 1) {
+ res.append('+');
+ }
+ res.append(c);
+ }
+ return res.toString();
+ }
+
+ public static String format(double number, NumberFormat format) {
+ if (Double.isNaN(number)) {
+ return padLeft(format, " NaN");
+ } else if (Double.isInfinite(number)) {
+ return padLeft(format, number > 0.0 ? " +Inf" : " -Inf");
+ }
+ return format.format(number);
+ }
+
+ private static String padLeft(NumberFormat format, String str) {
+ int len = format.format(0.0).length();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < len - str.length() + 1; i++) {
+ sb.append(" ");
+ }
+ return sb.append(str).toString();
+ }
+
+ public static boolean equals(float a, float b, float delta) {
+ return Float.floatToIntBits(a) == Float.floatToIntBits(b) || Math.abs(a - b) <= delta;
+ }
+
+ public static boolean equals(double a, double b, double delta) {
+ return Double.doubleToLongBits(a) == Double.doubleToLongBits(b) || Math.abs(a - b) <= delta;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/SimplexNoise.java b/src/main/java/com/jozufozu/flywheel/repack/joml/SimplexNoise.java
new file mode 100644
index 000000000..4b378a335
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/SimplexNoise.java
@@ -0,0 +1,485 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+/**
+ * A simplex noise algorithm for 2D, 3D and 4D input.
+ *
+ * It was originally authored by Stefan Gustavson.
+ *
+ * The original implementation can be found here: http://http://staffwww.itn.liu.se/.
+ */
+public class SimplexNoise {
+ private static class Vector3b {
+ byte x, y, z;
+ Vector3b(int x, int y, int z) {
+ super();
+ this.x = (byte) x;
+ this.y = (byte) y;
+ this.z = (byte) z;
+ }
+ }
+ private static class Vector4b {
+ byte x, y, z, w;
+ Vector4b(int x, int y, int z, int w) {
+ super();
+ this.x = (byte) x;
+ this.y = (byte) y;
+ this.z = (byte) z;
+ this.w = (byte) w;
+ }
+ }
+
+ // Kai Burjack:
+ // Use a three-component vector here to save memory. (instead of using 4-component 'Grad' class)
+ // And as the original author mentioned on the 'Grad' class, using a class to store the gradient components
+ // is indeed faster compared to using a simple int[] array...
+ private static final Vector3b[] grad3 = { new Vector3b(1, 1, 0), new Vector3b(-1, 1, 0), new Vector3b(1, -1, 0), new Vector3b(-1, -1, 0),
+ new Vector3b(1, 0, 1), new Vector3b(-1, 0, 1), new Vector3b(1, 0, -1), new Vector3b(-1, 0, -1), new Vector3b(0, 1, 1), new Vector3b(0, -1, 1),
+ new Vector3b(0, 1, -1), new Vector3b(0, -1, -1) };
+
+ // Kai Burjack:
+ // As the original author mentioned on the 'Grad' class, using a class to store the gradient components
+ // is indeed faster compared to using a simple int[] array...
+ private static final Vector4b[] grad4 = { new Vector4b(0, 1, 1, 1), new Vector4b(0, 1, 1, -1), new Vector4b(0, 1, -1, 1), new Vector4b(0, 1, -1, -1),
+ new Vector4b(0, -1, 1, 1), new Vector4b(0, -1, 1, -1), new Vector4b(0, -1, -1, 1), new Vector4b(0, -1, -1, -1), new Vector4b(1, 0, 1, 1),
+ new Vector4b(1, 0, 1, -1), new Vector4b(1, 0, -1, 1), new Vector4b(1, 0, -1, -1), new Vector4b(-1, 0, 1, 1), new Vector4b(-1, 0, 1, -1),
+ new Vector4b(-1, 0, -1, 1), new Vector4b(-1, 0, -1, -1), new Vector4b(1, 1, 0, 1), new Vector4b(1, 1, 0, -1), new Vector4b(1, -1, 0, 1),
+ new Vector4b(1, -1, 0, -1), new Vector4b(-1, 1, 0, 1), new Vector4b(-1, 1, 0, -1), new Vector4b(-1, -1, 0, 1), new Vector4b(-1, -1, 0, -1),
+ new Vector4b(1, 1, 1, 0), new Vector4b(1, 1, -1, 0), new Vector4b(1, -1, 1, 0), new Vector4b(1, -1, -1, 0), new Vector4b(-1, 1, 1, 0),
+ new Vector4b(-1, 1, -1, 0), new Vector4b(-1, -1, 1, 0), new Vector4b(-1, -1, -1, 0) };
+
+ // Kai Burjack:
+ // Use a byte[] instead of a short[] to save memory
+ private static final byte[] p = { -105, -96, -119, 91, 90, 15, -125, 13, -55, 95, 96, 53, -62, -23, 7, -31, -116, 36, 103, 30, 69, -114, 8, 99, 37, -16,
+ 21, 10, 23, -66, 6, -108, -9, 120, -22, 75, 0, 26, -59, 62, 94, -4, -37, -53, 117, 35, 11, 32, 57, -79, 33, 88, -19, -107, 56, 87, -82, 20, 125,
+ -120, -85, -88, 68, -81, 74, -91, 71, -122, -117, 48, 27, -90, 77, -110, -98, -25, 83, 111, -27, 122, 60, -45, -123, -26, -36, 105, 92, 41, 55, 46,
+ -11, 40, -12, 102, -113, 54, 65, 25, 63, -95, 1, -40, 80, 73, -47, 76, -124, -69, -48, 89, 18, -87, -56, -60, -121, -126, 116, -68, -97, 86, -92,
+ 100, 109, -58, -83, -70, 3, 64, 52, -39, -30, -6, 124, 123, 5, -54, 38, -109, 118, 126, -1, 82, 85, -44, -49, -50, 59, -29, 47, 16, 58, 17, -74,
+ -67, 28, 42, -33, -73, -86, -43, 119, -8, -104, 2, 44, -102, -93, 70, -35, -103, 101, -101, -89, 43, -84, 9, -127, 22, 39, -3, 19, 98, 108, 110,
+ 79, 113, -32, -24, -78, -71, 112, 104, -38, -10, 97, -28, -5, 34, -14, -63, -18, -46, -112, 12, -65, -77, -94, -15, 81, 51, -111, -21, -7, 14, -17,
+ 107, 49, -64, -42, 31, -75, -57, 106, -99, -72, 84, -52, -80, 115, 121, 50, 45, 127, 4, -106, -2, -118, -20, -51, 93, -34, 114, 67, 29, 24, 72,
+ -13, -115, -128, -61, 78, 66, -41, 61, -100, -76 };
+ // To remove the need for index wrapping, float the permutation table length
+ private static final byte[] perm = new byte[512];
+ private static final byte[] permMod12 = new byte[512];
+ static {
+ for (int i = 0; i < 512; i++) {
+ perm[i] = p[i & 255];
+ permMod12[i] = (byte) ((perm[i]&0xFF) % 12);
+ }
+ }
+
+ // Skewing and unskewing factors for 2, 3, and 4 dimensions
+ private static final float F2 = 0.3660254037844386f; // <- (float) (0.5f * (Math.sqrt(3.0f) - 1.0f));
+ private static final float G2 = 0.21132486540518713f; // <- (float) ((3.0f - Math.sqrt(3.0f)) / 6.0f);
+ private static final float F3 = 1.0f / 3.0f;
+ private static final float G3 = 1.0f / 6.0f;
+ private static final float F4 = 0.30901699437494745f; // <- (float) ((Math.sqrt(5.0f) - 1.0f) / 4.0f);
+ private static final float G4 = 0.1381966011250105f; // <- (float) ((5.0f - Math.sqrt(5.0f)) / 20.0f);
+
+ // This method is a *lot* faster than using (int)Math.floor(x)
+ private static int fastfloor(float x) {
+ int xi = (int) x;
+ return x < xi ? xi - 1 : xi;
+ }
+
+ private static float dot(Vector3b g, float x, float y) {
+ return g.x * x + g.y * y;
+ }
+
+ private static float dot(Vector3b g, float x, float y, float z) {
+ return g.x * x + g.y * y + g.z * z;
+ }
+
+ private static float dot(Vector4b g, float x, float y, float z, float w) {
+ return g.x * x + g.y * y + g.z * z + g.w * w;
+ }
+
+ /**
+ * Compute 2D simplex noise for the given input vector (x, y)
.
+ *
+ * The result is in the range [-1..+1]
.
+ *
+ * @param x
+ * the x coordinate
+ * @param y
+ * the y coordinate
+ * @return the noise value (within [-1..+1]
)
+ */
+ public static float noise(float x, float y) {
+ float n0, n1, n2; // Noise contributions from the three corners
+ // Skew the input space to determine which simplex cell we're in
+ float s = (x + y) * F2; // Hairy factor for 2D
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ float t = (i + j) * G2;
+ float X0 = i - t; // Unskew the cell origin back to (x,y) space
+ float Y0 = j - t;
+ float x0 = x - X0; // The x,y distances from the cell origin
+ float y0 = y - Y0;
+ // For the 2D case, the simplex shape is an equilateral triangle.
+ // Determine which simplex we are in.
+ int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
+ if (x0 > y0) {
+ i1 = 1;
+ j1 = 0;
+ } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
+ else {
+ i1 = 0;
+ j1 = 1;
+ } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
+ // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
+ // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
+ // c = (3-sqrt(3))/6
+ float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
+ float y1 = y0 - j1 + G2;
+ float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
+ float y2 = y0 - 1.0f + 2.0f * G2;
+ // Work out the hashed gradient indices of the three simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+ int gi0 = permMod12[ii + perm[jj]&0xFF]&0xFF;
+ int gi1 = permMod12[ii + i1 + perm[jj + j1]&0xFF]&0xFF;
+ int gi2 = permMod12[ii + 1 + perm[jj + 1]&0xFF]&0xFF;
+ // Calculate the contribution from the three corners
+ float t0 = 0.5f - x0 * x0 - y0 * y0;
+ if (t0 < 0.0f)
+ n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient
+ }
+ float t1 = 0.5f - x1 * x1 - y1 * y1;
+ if (t1 < 0.0f)
+ n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad3[gi1], x1, y1);
+ }
+ float t2 = 0.5f - x2 * x2 - y2 * y2;
+ if (t2 < 0.0f)
+ n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad3[gi2], x2, y2);
+ }
+ // Add contributions from each corner to get the final noise value.
+ // The result is scaled to return values in the interval [-1,1].
+ return 70.0f * (n0 + n1 + n2);
+ }
+
+ /**
+ * Compute 3D simplex noise for the given input vector (x, y, z)
.
+ *
+ * The result is in the range [-1..+1]
.
+ *
+ * @param x
+ * the x coordinate
+ * @param y
+ * the y coordinate
+ * @param z
+ * the z coordinate
+ * @return the noise value (within [-1..+1]
)
+ */
+ public static float noise(float x, float y, float z) {
+ float n0, n1, n2, n3; // Noise contributions from the four corners
+ // Skew the input space to determine which simplex cell we're in
+ float s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ int k = fastfloor(z + s);
+ float t = (i + j + k) * G3;
+ float X0 = i - t; // Unskew the cell origin back to (x,y,z) space
+ float Y0 = j - t;
+ float Z0 = k - t;
+ float x0 = x - X0; // The x,y,z distances from the cell origin
+ float y0 = y - Y0;
+ float z0 = z - Z0;
+ // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
+ // Determine which simplex we are in.
+ int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
+ int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
+ if (x0 >= y0) {
+ if (y0 >= z0) {
+ i1 = 1;
+ j1 = 0;
+ k1 = 0;
+ i2 = 1;
+ j2 = 1;
+ k2 = 0;
+ } // X Y Z order
+ else if (x0 >= z0) {
+ i1 = 1;
+ j1 = 0;
+ k1 = 0;
+ i2 = 1;
+ j2 = 0;
+ k2 = 1;
+ } // X Z Y order
+ else {
+ i1 = 0;
+ j1 = 0;
+ k1 = 1;
+ i2 = 1;
+ j2 = 0;
+ k2 = 1;
+ } // Z X Y order
+ } else { // x0(x, y, z, w).
+ *
+ * The result is in the range [-1..+1]
.
+ *
+ * @param x
+ * the x coordinate
+ * @param y
+ * the y coordinate
+ * @param z
+ * the z coordinate
+ * @param w
+ * the w coordinate
+ * @return the noise value (within [-1..+1]
)
+ */
+ public static float noise(float x, float y, float z, float w) {
+ float n0, n1, n2, n3, n4; // Noise contributions from the five corners
+ // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
+ float s = (x + y + z + w) * F4; // Factor for 4D skewing
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ int k = fastfloor(z + s);
+ int l = fastfloor(w + s);
+ float t = (i + j + k + l) * G4; // Factor for 4D unskewing
+ float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
+ float Y0 = j - t;
+ float Z0 = k - t;
+ float W0 = l - t;
+ float x0 = x - X0; // The x,y,z,w distances from the cell origin
+ float y0 = y - Y0;
+ float z0 = z - Z0;
+ float w0 = w - W0;
+ // For the 4D case, the simplex is a 4D shape I won't even try to describe.
+ // To find out which of the 24 possible simplices we're in, we need to
+ // determine the magnitude ordering of x0, y0, z0 and w0.
+ // Six pair-wise comparisons are performed between each possible pair
+ // of the four coordinates, and the results are used to rank the numbers.
+ int rankx = 0;
+ int ranky = 0;
+ int rankz = 0;
+ int rankw = 0;
+ if (x0 > y0)
+ rankx++;
+ else
+ ranky++;
+ if (x0 > z0)
+ rankx++;
+ else
+ rankz++;
+ if (x0 > w0)
+ rankx++;
+ else
+ rankw++;
+ if (y0 > z0)
+ ranky++;
+ else
+ rankz++;
+ if (y0 > w0)
+ ranky++;
+ else
+ rankw++;
+ if (z0 > w0)
+ rankz++;
+ else
+ rankw++;
+ int i1, j1, k1, l1; // The integer offsets for the second simplex corner
+ int i2, j2, k2, l2; // The integer offsets for the third simplex corner
+ int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
+ // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
+ // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0;
+ j1 = ranky >= 3 ? 1 : 0;
+ k1 = rankz >= 3 ? 1 : 0;
+ l1 = rankw >= 3 ? 1 : 0;
+ // Rank 2 denotes the second largest coordinate.
+ i2 = rankx >= 2 ? 1 : 0;
+ j2 = ranky >= 2 ? 1 : 0;
+ k2 = rankz >= 2 ? 1 : 0;
+ l2 = rankw >= 2 ? 1 : 0;
+ // Rank 1 denotes the second smallest coordinate.
+ i3 = rankx >= 1 ? 1 : 0;
+ j3 = ranky >= 1 ? 1 : 0;
+ k3 = rankz >= 1 ? 1 : 0;
+ l3 = rankw >= 1 ? 1 : 0;
+ // The fifth corner has all coordinate offsets = 1, so no need to compute that.
+ float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
+ float y1 = y0 - j1 + G4;
+ float z1 = z0 - k1 + G4;
+ float w1 = w0 - l1 + G4;
+ float x2 = x0 - i2 + 2.0f * G4; // Offsets for third corner in (x,y,z,w) coords
+ float y2 = y0 - j2 + 2.0f * G4;
+ float z2 = z0 - k2 + 2.0f * G4;
+ float w2 = w0 - l2 + 2.0f * G4;
+ float x3 = x0 - i3 + 3.0f * G4; // Offsets for fourth corner in (x,y,z,w) coords
+ float y3 = y0 - j3 + 3.0f * G4;
+ float z3 = z0 - k3 + 3.0f * G4;
+ float w3 = w0 - l3 + 3.0f * G4;
+ float x4 = x0 - 1.0f + 4.0f * G4; // Offsets for last corner in (x,y,z,w) coords
+ float y4 = y0 - 1.0f + 4.0f * G4;
+ float z4 = z0 - 1.0f + 4.0f * G4;
+ float w4 = w0 - 1.0f + 4.0f * G4;
+ // Work out the hashed gradient indices of the five simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+ int kk = k & 255;
+ int ll = l & 255;
+ int gi0 = (perm[ii + perm[jj + perm[kk + perm[ll]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi3 = (perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi4 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ // Calculate the contribution from the five corners
+ float t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0;
+ if (t0 < 0.0f)
+ n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
+ }
+ float t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1;
+ if (t1 < 0.0f)
+ n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
+ }
+ float t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2;
+ if (t2 < 0.0f)
+ n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
+ }
+ float t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3;
+ if (t3 < 0.0f)
+ n3 = 0.0f;
+ else {
+ t3 *= t3;
+ n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
+ }
+ float t4 = 0.6f - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4;
+ if (t4 < 0.0f)
+ n4 = 0.0f;
+ else {
+ t4 *= t4;
+ n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
+ }
+ // Sum up and scale the result to cover the range [-1,1]
+ return 27.0f * (n0 + n1 + n2 + n3 + n4);
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2d.java
new file mode 100644
index 000000000..ccc36cf88
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2d.java
@@ -0,0 +1,1364 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Represents a 2D vector with double-precision.
+ *
+ * @author RGreenlees
+ * @author Kai Burjack
+ * @author F. Neurath
+ */
+public class Vector2d implements Externalizable, Cloneable, Vector2dc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public double x;
+ /**
+ * The y component of the vector.
+ */
+ public double y;
+
+ /**
+ * Create a new {@link Vector2d} and initialize its components to zero.
+ */
+ public Vector2d() {
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize both of its components with the given value.
+ *
+ * @param d
+ * the value of both components
+ */
+ public Vector2d(double d) {
+ this.x = d;
+ this.y = d;
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize its components to the given values.
+ *
+ * @param x
+ * the x value
+ * @param y
+ * the y value
+ */
+ public Vector2d(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize its components to the one of the given vector.
+ *
+ * @param v
+ * the {@link Vector2dc} to copy the values from
+ */
+ public Vector2d(Vector2dc v) {
+ x = v.x();
+ y = v.y();
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize its components to the one of the given vector.
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ */
+ public Vector2d(Vector2fc v) {
+ x = v.x();
+ y = v.y();
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize its components to the one of the given vector.
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ */
+ public Vector2d(Vector2ic v) {
+ x = v.x();
+ y = v.y();
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize its two components from the first
+ * two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least three elements
+ */
+ public Vector2d(double[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ }
+
+ /**
+ * Create a new {@link Vector2d} and initialize its two components from the first
+ * two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least two elements
+ */
+ public Vector2d(float[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ }
+
+ /**
+ * Create a new {@link Vector2d} and read this vector from the supplied {@link ByteBuffer}
+ * at the current buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #Vector2d(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @see #Vector2d(int, ByteBuffer)
+ */
+ public Vector2d(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2d} and read this vector from the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2d(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2d} and read this vector from the supplied {@link DoubleBuffer}
+ * at the current buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is read, use {@link #Vector2d(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @see #Vector2d(int, DoubleBuffer)
+ */
+ public Vector2d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2d} and read this vector from the supplied {@link DoubleBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2d(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public double x() {
+ return this.x;
+ }
+
+ public double y() {
+ return this.y;
+ }
+
+ /**
+ * Set the x and y components to the supplied value.
+ *
+ * @param d
+ * the value of both components
+ * @return this
+ */
+ public Vector2d set(double d) {
+ this.x = d;
+ this.y = d;
+ return this;
+ }
+
+ /**
+ * Set the x and y components to the supplied values.
+ *
+ * @param x
+ * the x value
+ * @param y
+ * the y value
+ * @return this
+ */
+ public Vector2d set(double x, double y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2d} to the values of v.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2d set(Vector2dc v) {
+ this.x = v.x();
+ this.y = v.y();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2d} to be a clone of v
.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2d set(Vector2fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2d} to be a clone of v
.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2d set(Vector2ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ return this;
+ }
+
+ /**
+ * Set the two components of this vector to the first two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least three elements
+ * @return this
+ */
+ public Vector2d set(double[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ return this;
+ }
+
+ /**
+ * Set the two components of this vector to the first two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least two elements
+ * @return this
+ */
+ public Vector2d set(float[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #set(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ * @see #set(int, ByteBuffer)
+ */
+ public Vector2d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is read, use {@link #set(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ * @see #set(int, DoubleBuffer)
+ */
+ public Vector2d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 2 double values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector2d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ public double get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Vector2i get(int mode, Vector2i dest) {
+ dest.x = Math.roundUsing(this.x(), mode);
+ dest.y = Math.roundUsing(this.y(), mode);
+ return dest;
+ }
+
+ public Vector2f get(Vector2f dest) {
+ dest.x = (float) this.x();
+ dest.y = (float) this.y();
+ return dest;
+ }
+
+ public Vector2d get(Vector2d dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ return dest;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..1]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..1]
+ */
+ public Vector2d setComponent(int component, double value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector2dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Set this vector to be one of its perpendicular vectors.
+ *
+ * @return this
+ */
+ public Vector2d perpendicular() {
+ double xTemp = y;
+ this.y = x * -1;
+ this.x = xTemp;
+ return this;
+ }
+
+ /**
+ * Subtract v
from this vector.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector2d sub(Vector2dc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ return this;
+ }
+
+ /**
+ * Subtract (x, y)
from this vector.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @return this
+ */
+ public Vector2d sub(double x, double y) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ return this;
+ }
+
+ public Vector2d sub(double x, double y, Vector2d dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ return dest;
+ }
+
+ /**
+ * Subtract v
from this vector.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector2d sub(Vector2fc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ return this;
+ }
+
+ public Vector2d sub(Vector2dc v, Vector2d dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ return dest;
+ }
+
+ public Vector2d sub(Vector2fc v, Vector2d dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this vector by the given scalar.
+ *
+ * @param scalar
+ * the value to multiply this vector's components by
+ * @return this
+ */
+ public Vector2d mul(double scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ return this;
+ }
+
+ public Vector2d mul(double scalar, Vector2d dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this Vector2d by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @return this
+ */
+ public Vector2d mul(double x, double y) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ return this;
+ }
+
+ public Vector2d mul(double x, double y, Vector2d dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector2d component-wise by another Vector2d.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector2d mul(Vector2dc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ return this;
+ }
+
+ public Vector2d mul(Vector2dc v, Vector2d dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ return dest;
+ }
+
+ /**
+ * Divide this Vector2d by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide this vector by
+ * @return this
+ */
+ public Vector2d div(double scalar) {
+ double inv = 1.0 / scalar;
+ this.x = x * inv;
+ this.y = y * inv;
+ return this;
+ }
+
+ public Vector2d div(double scalar, Vector2d dest) {
+ double inv = 1.0 / scalar;
+ dest.x = x * inv;
+ dest.y = y * inv;
+ return dest;
+ }
+
+ /**
+ * Divide the components of this Vector2d by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @return this
+ */
+ public Vector2d div(double x, double y) {
+ this.x = this.x / x;
+ this.y = this.y / y;
+ return this;
+ }
+
+ public Vector2d div(double x, double y, Vector2d dest) {
+ dest.x = this.x / x;
+ dest.y = this.y / y;
+ return dest;
+ }
+
+ /**
+ * Divide this Vector2d component-wise by another Vector2dc.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector2d div(Vector2d v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ return this;
+ }
+
+ /**
+ * Divide this Vector3d component-wise by another Vector2fc.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector2d div(Vector2fc v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ return this;
+ }
+
+ public Vector2d div(Vector2fc v, Vector2d dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ return dest;
+ }
+
+ public Vector2d div(Vector2dc v, Vector2d dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector2d.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector2d mul(Matrix2fc mat) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector2d.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector2d mul(Matrix2dc mat) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2d mul(Matrix2dc mat, Vector2d dest) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ public Vector2d mul(Matrix2fc mat, Vector2d dest) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector2d and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector2d mulTranspose(Matrix2dc mat) {
+ double rx = mat.m00() * x + mat.m01() * y;
+ double ry = mat.m10() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2d mulTranspose(Matrix2dc mat, Vector2d dest) {
+ double rx = mat.m00() * x + mat.m01() * y;
+ double ry = mat.m10() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector2d and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector2d mulTranspose(Matrix2fc mat) {
+ double rx = mat.m00() * x + mat.m01() * y;
+ double ry = mat.m10() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2d mulTranspose(Matrix2fc mat, Vector2d dest) {
+ double rx = mat.m00() * x + mat.m01() * y;
+ double ry = mat.m10() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
.
+ *
+ * This method assumes the z
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector2d mulPosition(Matrix3x2dc mat) {
+ double rx = mat.m00() * x + mat.m10() * y + mat.m20();
+ double ry = mat.m01() * x + mat.m11() * y + mat.m21();
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2d mulPosition(Matrix3x2dc mat, Vector2d dest) {
+ double rx = mat.m00() * x + mat.m10() * y + mat.m20();
+ double ry = mat.m01() * x + mat.m11() * y + mat.m21();
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
.
+ *
+ * This method assumes the z
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector2d mulDirection(Matrix3x2dc mat) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2d mulDirection(Matrix3x2dc mat, Vector2d dest) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ public double dot(Vector2dc v) {
+ return x * v.x() + y * v.y();
+ }
+
+ public double angle(Vector2dc v) {
+ double dot = x*v.x() + y*v.y();
+ double det = x*v.y() - y*v.x();
+ return Math.atan2(det, dot);
+ }
+
+ public double lengthSquared() {
+ return x * x + y * y;
+ }
+
+ /**
+ * Get the length squared of a 2-dimensional double-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ *
+ * @return the length squared of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static double lengthSquared(double x, double y) {
+ return x * x + y * y;
+ }
+
+ public double length() {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ /**
+ * Get the length of a 2-dimensional double-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ *
+ * @return the length of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static double length(double x, double y) {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ public double distance(Vector2dc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public double distanceSquared(Vector2dc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ return dx * dx + dy * dy;
+ }
+
+ public double distance(Vector2fc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public double distanceSquared(Vector2fc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ return dx * dx + dy * dy;
+ }
+
+ public double distance(double x, double y) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public double distanceSquared(double x, double y) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ return dx * dx + dy * dy;
+ }
+
+ /**
+ * Return the distance between (x1, y1)
and (x2, y2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @return the euclidean distance
+ */
+ public static double distance(double x1, double y1, double x2, double y2) {
+ double dx = x1 - x2;
+ double dy = y1 - y2;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ /**
+ * Return the squared distance between (x1, y1)
and (x2, y2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static double distanceSquared(double x1, double y1, double x2, double y2) {
+ double dx = x1 - x2;
+ double dy = y1 - y2;
+ return dx * dx + dy * dy;
+ }
+
+ /**
+ * Normalize this vector.
+ *
+ * @return this
+ */
+ public Vector2d normalize() {
+ double invLength = Math.invsqrt(x * x + y * y);
+ this.x = x * invLength;
+ this.y = y * invLength;
+ return this;
+ }
+
+ public Vector2d normalize(Vector2d dest) {
+ double invLength = Math.invsqrt(x * x + y * y);
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ return dest;
+ }
+
+ /**
+ * Scale this vector to have the given length.
+ *
+ * @param length
+ * the desired length
+ * @return this
+ */
+ public Vector2d normalize(double length) {
+ double invLength = Math.invsqrt(x * x + y * y) * length;
+ this.x = x * invLength;
+ this.y = y * invLength;
+ return this;
+ }
+
+ public Vector2d normalize(double length, Vector2d dest) {
+ double invLength = Math.invsqrt(x * x + y * y) * length;
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ return dest;
+ }
+
+ /**
+ * Add v
to this vector.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector2d add(Vector2dc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ return this;
+ }
+
+ /**
+ * Add (x, y)
to this vector.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @return this
+ */
+ public Vector2d add(double x, double y) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ return this;
+ }
+
+ public Vector2d add(double x, double y, Vector2d dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ return dest;
+ }
+
+ /**
+ * Add v
to this vector.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector2d add(Vector2fc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ return this;
+ }
+
+ public Vector2d add(Vector2dc v, Vector2d dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ return dest;
+ }
+
+ public Vector2d add(Vector2fc v, Vector2d dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ return dest;
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector2d zero() {
+ this.x = 0;
+ this.y = 0;
+ return this;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(x);
+ out.writeDouble(y);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ x = in.readDouble();
+ y = in.readDouble();
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector2d negate() {
+ this.x = -x;
+ this.y = -y;
+ return this;
+ }
+
+ public Vector2d negate(Vector2d dest) {
+ dest.x = -x;
+ dest.y = -y;
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Vector2d lerp(Vector2dc other, double t) {
+ this.x = x + (other.x() - x) * t;
+ this.y = y + (other.y() - y) * t;
+ return this;
+ }
+
+ public Vector2d lerp(Vector2dc other, double t, Vector2d dest) {
+ dest.x = x + (other.x() - x) * t;
+ dest.y = y + (other.y() - y) * t;
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(x);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(y);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Vector2d other = (Vector2d) obj;
+ if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
+ return false;
+ if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Vector2dc v, double delta) {
+ if (this == v)
+ return true;
+ if (v == null)
+ return false;
+ if (!(v instanceof Vector2dc))
+ return false;
+ if (!Runtime.equals(x, v.x(), delta))
+ return false;
+ if (!Runtime.equals(y, v.y(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(double x, double y) {
+ if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(x))
+ return false;
+ if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(y))
+ return false;
+ return true;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + ")";
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector2d fma(Vector2dc a, Vector2dc b) {
+ this.x = x + a.x() * b.x();
+ this.y = y + a.y() * b.y();
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector2d fma(double a, Vector2dc b) {
+ this.x = x + a * b.x();
+ this.y = y + a * b.y();
+ return this;
+ }
+
+ public Vector2d fma(Vector2dc a, Vector2dc b, Vector2d dest) {
+ dest.x = x + a.x() * b.x();
+ dest.y = y + a.y() * b.y();
+ return dest;
+ }
+
+ public Vector2d fma(double a, Vector2dc b, Vector2d dest) {
+ dest.x = x + a * b.x();
+ dest.y = y + a * b.y();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector2d min(Vector2dc v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ return this;
+ }
+
+ public Vector2d min(Vector2dc v, Vector2d dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector2d max(Vector2dc v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ return this;
+ }
+
+ public Vector2d max(Vector2dc v, Vector2d dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ return dest;
+ }
+
+ public int maxComponent() {
+ double absX = Math.abs(x);
+ double absY = Math.abs(y);
+ if (absX >= absY)
+ return 0;
+ return 1;
+ }
+
+ public int minComponent() {
+ double absX = Math.abs(x);
+ double absY = Math.abs(y);
+ if (absX < absY)
+ return 0;
+ return 1;
+ }
+
+ /**
+ * Set each component of this vector to the largest (closest to positive
+ * infinity) {@code double} value that is less than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector2d floor() {
+ this.x = Math.floor(x);
+ this.y = Math.floor(y);
+ return this;
+ }
+
+ public Vector2d floor(Vector2d dest) {
+ dest.x = Math.floor(x);
+ dest.y = Math.floor(y);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the smallest (closest to negative
+ * infinity) {@code double} value that is greater than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector2d ceil() {
+ this.x = Math.ceil(x);
+ this.y = Math.ceil(y);
+ return this;
+ }
+
+ public Vector2d ceil(Vector2d dest) {
+ dest.x = Math.ceil(x);
+ dest.y = Math.ceil(y);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the closest double that is equal to
+ * a mathematical integer, with ties rounding to positive infinity.
+ *
+ * @return this
+ */
+ public Vector2d round() {
+ this.x = Math.round(x);
+ this.y = Math.round(y);
+ return this;
+ }
+
+ public Vector2d round(Vector2d dest) {
+ dest.x = Math.round(x);
+ dest.y = Math.round(y);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y);
+ }
+
+ /**
+ * Set this
vector's components to their respective absolute values.
+ *
+ * @return this
+ */
+ public Vector2d absolute() {
+ this.x = Math.abs(this.x);
+ this.y = Math.abs(this.y);
+ return this;
+ }
+
+ public Vector2d absolute(Vector2d dest) {
+ dest.x = Math.abs(this.x);
+ dest.y = Math.abs(this.y);
+ return dest;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2dc.java
new file mode 100644
index 000000000..eb396da52
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2dc.java
@@ -0,0 +1,670 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 2-dimensional vector of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector2dc {
+
+ /**
+ * @return the value of the x component
+ */
+ double x();
+
+ /**
+ * @return the value of the y component
+ */
+ double y();
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ * @see #get(int, DoubleBuffer)
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector2dc getToAddress(long address);
+
+ /**
+ * Subtract (x, y)
from this vector and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d sub(double x, double y, Vector2d dest);
+
+ /**
+ * Subtract v
from this
vector and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d sub(Vector2dc v, Vector2d dest);
+
+ /**
+ * Subtract v
from this
vector and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d sub(Vector2fc v, Vector2d dest);
+
+ /**
+ * Multiply the components of this vector by the given scalar and store the result in dest
.
+ *
+ * @param scalar
+ * the value to multiply this vector's components by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mul(double scalar, Vector2d dest);
+
+ /**
+ * Multiply the components of this Vector2d by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mul(double x, double y, Vector2d dest);
+
+ /**
+ * Multiply this Vector2d component-wise by another Vector2d and store the result in dest
.
+ *
+ * @param v
+ * the vector to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mul(Vector2dc v, Vector2d dest);
+
+ /**
+ * Divide this Vector2d by the given scalar value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d div(double scalar, Vector2d dest);
+
+ /**
+ * Divide the components of this Vector3f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d div(double x, double y, Vector2d dest);
+
+ /**
+ * Divide this Vector2d component-wise by another Vector2f and store the result in dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d div(Vector2fc v, Vector2d dest);
+
+ /**
+ * Divide this by v
component-wise and store the result into dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d div(Vector2dc v, Vector2d dest);
+
+ /**
+ * Multiply the given matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mul(Matrix2dc mat, Vector2d dest);
+
+ /**
+ * Multiply the given matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mul(Matrix2fc mat, Vector2d dest);
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector2f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mulTranspose(Matrix2dc mat, Vector2d dest);
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector2f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mulTranspose(Matrix2fc mat, Vector2d dest);
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the z
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mulPosition(Matrix3x2dc mat, Vector2d dest);
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the z
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d mulDirection(Matrix3x2dc mat, Vector2d dest);
+
+ /**
+ * Return the dot product of this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ double dot(Vector2dc v);
+
+ /**
+ * Return the angle between this vector and the supplied vector.
+ *
+ * @param v
+ * the other vector
+ * @return the angle, in radians
+ */
+ double angle(Vector2dc v);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ double lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ double length();
+
+ /**
+ * Return the distance between this and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector2dc v);
+
+ /**
+ * Return the distance squared between this and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance squared
+ */
+ double distanceSquared(Vector2dc v);
+
+ /**
+ * Return the distance between this and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector2fc v);
+
+ /**
+ * Return the distance squared between this and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance squared
+ */
+ double distanceSquared(Vector2fc v);
+
+ /**
+ * Return the distance between this
vector and (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the euclidean distance
+ */
+ double distance(double x, double y);
+
+ /**
+ * Return the distance squared between this
vector and (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the euclidean distance squared
+ */
+ double distanceSquared(double x, double y);
+
+ /**
+ * Normalize this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d normalize(Vector2d dest);
+
+ /**
+ * Scale this vector to have the given length and store the result in dest
.
+ *
+ * @param length
+ * the desired length
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d normalize(double length, Vector2d dest);
+
+ /**
+ * Add (x, y)
to this vector and store the result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d add(double x, double y, Vector2d dest);
+
+ /**
+ * Add v
to this vector and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d add(Vector2dc v, Vector2d dest);
+
+ /**
+ * Add v
to this vector and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d add(Vector2fc v, Vector2d dest);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d negate(Vector2d dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d lerp(Vector2dc other, double t, Vector2d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d fma(Vector2dc a, Vector2dc b, Vector2d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d fma(double a, Vector2dc b, Vector2d dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d min(Vector2dc v, Vector2d dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d max(Vector2dc v, Vector2d dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..1]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..1]
+ */
+ int minComponent();
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..1]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..1]
+ */
+ double get(int component) throws IllegalArgumentException;
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector
+ * using the given {@link RoundingMode}.
+ *
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i get(int mode, Vector2i dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f get(Vector2f dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d get(Vector2d dest);
+
+ /**
+ * Compute for each component of this vector the largest (closest to positive
+ * infinity) {@code double} value that is less than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d floor(Vector2d dest);
+
+ /**
+ * Compute for each component of this vector the smallest (closest to negative
+ * infinity) {@code double} value that is greater than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d ceil(Vector2d dest);
+
+ /**
+ * Compute for each component of this vector the closest double that is equal to
+ * a mathematical integer, with ties rounding to positive infinity and store
+ * the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d round(Vector2d dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d absolute(Vector2d dest);
+
+ /**
+ * Compare the vector components of this
vector with the given vector using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param v
+ * the other vector
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the vector components are equal; false
otherwise
+ */
+ boolean equals(Vector2dc v, double delta);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(double x, double y);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2f.java
new file mode 100644
index 000000000..148f885af
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2f.java
@@ -0,0 +1,1252 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Represents a 2D vector with single-precision.
+ *
+ * @author RGreenlees
+ * @author Kai Burjack
+ * @author F. Neurath
+ */
+public class Vector2f implements Externalizable, Cloneable, Vector2fc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public float x;
+ /**
+ * The y component of the vector.
+ */
+ public float y;
+
+ /**
+ * Create a new {@link Vector2f} and initialize its components to zero.
+ */
+ public Vector2f() {
+ }
+
+ /**
+ * Create a new {@link Vector2f} and initialize both of its components with the given value.
+ *
+ * @param d
+ * the value of both components
+ */
+ public Vector2f(float d) {
+ this.x = d;
+ this.y = d;
+ }
+
+ /**
+ * Create a new {@link Vector2f} and initialize its components to the given values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ */
+ public Vector2f(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Create a new {@link Vector2f} and initialize its components to the one of the given vector.
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ */
+ public Vector2f(Vector2fc v) {
+ x = v.x();
+ y = v.y();
+ }
+
+ /**
+ * Create a new {@link Vector2f} and initialize its components to the one of the given vector.
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ */
+ public Vector2f(Vector2ic v) {
+ x = v.x();
+ y = v.y();
+ }
+
+ /**
+ * Create a new {@link Vector2f} and initialize its two components from the first
+ * two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least two elements
+ */
+ public Vector2f(float[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ }
+
+ /**
+ * Create a new {@link Vector2f} and read this vector from the supplied {@link ByteBuffer}
+ * at the current buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #Vector2f(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @see #Vector2f(int, ByteBuffer)
+ */
+ public Vector2f(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2f} and read this vector from the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer values will be read in x, y
order
+ */
+ public Vector2f(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2f} and read this vector from the supplied {@link FloatBuffer}
+ * at the current buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is read, use {@link #Vector2f(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @see #Vector2f(int, FloatBuffer)
+ */
+ public Vector2f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2f} and read this vector from the supplied {@link FloatBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2f(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public float x() {
+ return this.x;
+ }
+
+ public float y() {
+ return this.y;
+ }
+
+ /**
+ * Set the x and y components to the supplied value.
+ *
+ * @param d
+ * the value of both components
+ * @return this
+ */
+ public Vector2f set(float d) {
+ this.x = d;
+ this.y = d;
+ return this;
+ }
+
+ /**
+ * Set the x and y components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @return this
+ */
+ public Vector2f set(float x, float y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ /**
+ * Set the x and y components to the supplied value.
+ *
+ * @param d
+ * the value of both components
+ * @return this
+ */
+ public Vector2f set(double d) {
+ this.x = (float) d;
+ this.y = (float) d;
+ return this;
+ }
+
+ /**
+ * Set the x and y components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @return this
+ */
+ public Vector2f set(double x, double y) {
+ this.x = (float) x;
+ this.y = (float) y;
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2f} to the values of v.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2f set(Vector2fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2f} to the values of v.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2f set(Vector2ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2f} to the values of v.
+ *
+ * Note that due to the given vector v
storing the components in double-precision,
+ * there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2f set(Vector2dc v) {
+ this.x = (float) v.x();
+ this.y = (float) v.y();
+ return this;
+ }
+
+ /**
+ * Set the two components of this vector to the first two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least two elements
+ * @return this
+ */
+ public Vector2f set(float[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #set(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ * @see #set(int, ByteBuffer)
+ */
+ public Vector2f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is read, use {@link #set(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ * @see #set(int, FloatBuffer)
+ */
+ public Vector2f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 2 float values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector2f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ public float get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Vector2i get(int mode, Vector2i dest) {
+ dest.x = Math.roundUsing(this.x(), mode);
+ dest.y = Math.roundUsing(this.y(), mode);
+ return dest;
+ }
+
+ public Vector2f get(Vector2f dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ return dest;
+ }
+
+ public Vector2d get(Vector2d dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ return dest;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..1]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..1]
+ */
+ public Vector2f setComponent(int component, float value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector2fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Set this vector to be one of its perpendicular vectors.
+ *
+ * @return this
+ */
+ public Vector2f perpendicular() {
+ float xTemp = y;
+ this.y = this.x * -1;
+ this.x = xTemp;
+ return this;
+ }
+
+ /**
+ * Subtract v
from this vector.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector2f sub(Vector2fc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ return this;
+ }
+
+ public Vector2f sub(Vector2fc v, Vector2f dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ return dest;
+ }
+
+ /**
+ * Subtract (x, y)
from this vector.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @return this
+ */
+ public Vector2f sub(float x, float y) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ return this;
+ }
+
+ public Vector2f sub(float x, float y, Vector2f dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ return dest;
+ }
+
+ public float dot(Vector2fc v) {
+ return x * v.x() + y * v.y();
+ }
+
+ public float angle(Vector2fc v) {
+ float dot = x*v.x() + y*v.y();
+ float det = x*v.y() - y*v.x();
+ return Math.atan2(det, dot);
+ }
+
+ public float lengthSquared() {
+ return x * x + y * y;
+ }
+
+ /**
+ * Get the length squared of a 2-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ *
+ * @return the length squared of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static float lengthSquared(float x, float y) {
+ return x * x + y * y;
+ }
+
+ public float length() {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ /**
+ * Get the length of a 2-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ *
+ * @return the length of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static float length(float x, float y) {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ public float distance(Vector2fc v) {
+ float dx = this.x - v.x();
+ float dy = this.y - v.y();
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public float distanceSquared(Vector2fc v) {
+ float dx = this.x - v.x();
+ float dy = this.y - v.y();
+ return dx * dx + dy * dy;
+ }
+
+ public float distance(float x, float y) {
+ float dx = this.x - x;
+ float dy = this.y - y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public float distanceSquared(float x, float y) {
+ float dx = this.x - x;
+ float dy = this.y - y;
+ return dx * dx + dy * dy;
+ }
+
+ /**
+ * Return the distance between (x1, y1)
and (x2, y2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @return the euclidean distance
+ */
+ public static float distance(float x1, float y1, float x2, float y2) {
+ float dx = x1 - x2;
+ float dy = y1 - y2;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ /**
+ * Return the squared distance between (x1, y1)
and (x2, y2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static float distanceSquared(float x1, float y1, float x2, float y2) {
+ float dx = x1 - x2;
+ float dy = y1 - y2;
+ return dx * dx + dy * dy;
+ }
+
+ /**
+ * Normalize this vector.
+ *
+ * @return this
+ */
+ public Vector2f normalize() {
+ float invLength = Math.invsqrt(x * x + y * y);
+ this.x = x * invLength;
+ this.y = y * invLength;
+ return this;
+ }
+
+ public Vector2f normalize(Vector2f dest) {
+ float invLength = Math.invsqrt(x * x + y * y);
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ return dest;
+ }
+
+ /**
+ * Scale this vector to have the given length.
+ *
+ * @param length
+ * the desired length
+ * @return this
+ */
+ public Vector2f normalize(float length) {
+ float invLength = Math.invsqrt(x * x + y * y) * length;
+ this.x = x * invLength;
+ this.y = y * invLength;
+ return this;
+ }
+
+ public Vector2f normalize(float length, Vector2f dest) {
+ float invLength = Math.invsqrt(x * x + y * y) * length;
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ return dest;
+ }
+
+ /**
+ * Add v
to this vector.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector2f add(Vector2fc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ return this;
+ }
+
+ public Vector2f add(Vector2fc v, Vector2f dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @return this
+ */
+ public Vector2f add(float x, float y) {
+ return add(x, y, this);
+ }
+
+ public Vector2f add(float x, float y, Vector2f dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ return dest;
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector2f zero() {
+ this.x = 0;
+ this.y = 0;
+ return this;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(x);
+ out.writeFloat(y);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ x = in.readFloat();
+ y = in.readFloat();
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector2f negate() {
+ this.x = -x;
+ this.y = -y;
+ return this;
+ }
+
+ public Vector2f negate(Vector2f dest) {
+ dest.x = -x;
+ dest.y = -y;
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this vector by the given scalar.
+ *
+ * @param scalar
+ * the value to multiply this vector's components by
+ * @return this
+ */
+ public Vector2f mul(float scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ return this;
+ }
+
+ public Vector2f mul(float scalar, Vector2f dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this Vector2f by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @return this
+ */
+ public Vector2f mul(float x, float y) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ return this;
+ }
+
+ public Vector2f mul(float x, float y, Vector2f dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector2f component-wise by another Vector2f.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector2f mul(Vector2fc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ return this;
+ }
+
+ public Vector2f mul(Vector2fc v, Vector2f dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ return dest;
+ }
+
+ /**
+ * Divide this Vector2f component-wise by another Vector2fc.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector2f div(Vector2fc v) {
+ this.x = this.x / v.x();
+ this.y = this.y / v.y();
+ return this;
+ }
+
+ public Vector2f div(Vector2fc v, Vector2f dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector2f} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector2f div(float scalar) {
+ float inv = 1.0f / scalar;
+ this.x = this.x * inv;
+ this.y = this.y * inv;
+ return this;
+ }
+
+ public Vector2f div(float scalar, Vector2f dest) {
+ float inv = 1.0f / scalar;
+ dest.x = this.x * inv;
+ dest.y = this.y * inv;
+ return dest;
+ }
+
+ /**
+ * Divide the components of this Vector2f by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @return this
+ */
+ public Vector2f div(float x, float y) {
+ this.x = this.x / x;
+ this.y = this.y / y;
+ return this;
+ }
+
+ public Vector2f div(float x, float y, Vector2f dest) {
+ dest.x = this.x / x;
+ dest.y = this.y / y;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector2f and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector2f mul(Matrix2fc mat) {
+ float rx = mat.m00() * x + mat.m10() * y;
+ float ry = mat.m01() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2f mul(Matrix2fc mat, Vector2f dest) {
+ float rx = mat.m00() * x + mat.m10() * y;
+ float ry = mat.m01() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector2f and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector2f mul(Matrix2dc mat) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ this.x = (float) rx;
+ this.y = (float) ry;
+ return this;
+ }
+
+ public Vector2f mul(Matrix2dc mat, Vector2f dest) {
+ double rx = mat.m00() * x + mat.m10() * y;
+ double ry = mat.m01() * x + mat.m11() * y;
+ dest.x = (float) rx;
+ dest.y = (float) ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector2f store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector2f mulTranspose(Matrix2fc mat) {
+ float rx = mat.m00() * x + mat.m01() * y;
+ float ry = mat.m10() * x + mat.m11() * y;
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector2f mulTranspose(Matrix2fc mat, Vector2f dest) {
+ float rx = mat.m00() * x + mat.m01() * y;
+ float ry = mat.m10() * x + mat.m11() * y;
+ dest.x = rx;
+ dest.y = ry;
+ return dest;
+ }
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
.
+ *
+ * This method assumes the z
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector2f mulPosition(Matrix3x2fc mat) {
+ this.x = mat.m00() * x + mat.m10() * y + mat.m20();
+ this.y = mat.m01() * x + mat.m11() * y + mat.m21();
+ return this;
+ }
+
+ public Vector2f mulPosition(Matrix3x2fc mat, Vector2f dest) {
+ dest.x = mat.m00() * x + mat.m10() * y + mat.m20();
+ dest.y = mat.m01() * x + mat.m11() * y + mat.m21();
+ return dest;
+ }
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
.
+ *
+ * This method assumes the z
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector2f mulDirection(Matrix3x2fc mat) {
+ this.x = mat.m00() * x + mat.m10() * y;
+ this.y = mat.m01() * x + mat.m11() * y;
+ return this;
+ }
+
+ public Vector2f mulDirection(Matrix3x2fc mat, Vector2f dest) {
+ dest.x = mat.m00() * x + mat.m10() * y;
+ dest.y = mat.m01() * x + mat.m11() * y;
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Vector2f lerp(Vector2fc other, float t) {
+ this.x = x + (other.x() - x) * t;
+ this.y = y + (other.y() - y) * t;
+ return this;
+ }
+
+ public Vector2f lerp(Vector2fc other, float t, Vector2f dest) {
+ dest.x = x + (other.x() - x) * t;
+ dest.y = y + (other.y() - y) * t;
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(x);
+ result = prime * result + Float.floatToIntBits(y);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Vector2f other = (Vector2f) obj;
+ if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
+ return false;
+ if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Vector2fc v, float delta) {
+ if (this == v)
+ return true;
+ if (v == null)
+ return false;
+ if (!(v instanceof Vector2fc))
+ return false;
+ if (!Runtime.equals(x, v.x(), delta))
+ return false;
+ if (!Runtime.equals(y, v.y(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(float x, float y) {
+ if (Float.floatToIntBits(this.x) != Float.floatToIntBits(x))
+ return false;
+ if (Float.floatToIntBits(this.y) != Float.floatToIntBits(y))
+ return false;
+ return true;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + ")";
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector2f fma(Vector2fc a, Vector2fc b) {
+ this.x = x + a.x() * b.x();
+ this.y = y + a.y() * b.y();
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector2f fma(float a, Vector2fc b) {
+ this.x = x + a * b.x();
+ this.y = y + a * b.y();
+ return this;
+ }
+
+ public Vector2f fma(Vector2fc a, Vector2fc b, Vector2f dest) {
+ dest.x = x + a.x() * b.x();
+ dest.y = y + a.y() * b.y();
+ return dest;
+ }
+
+ public Vector2f fma(float a, Vector2fc b, Vector2f dest) {
+ dest.x = x + a * b.x();
+ dest.y = y + a * b.y();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector2f min(Vector2fc v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ return this;
+ }
+
+ public Vector2f min(Vector2fc v, Vector2f dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector2f max(Vector2fc v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ return this;
+ }
+
+ public Vector2f max(Vector2fc v, Vector2f dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ return dest;
+ }
+
+ public int maxComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ if (absX >= absY)
+ return 0;
+ return 1;
+ }
+
+ public int minComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ if (absX < absY)
+ return 0;
+ return 1;
+ }
+
+ /**
+ * Set each component of this vector to the largest (closest to positive
+ * infinity) {@code float} value that is less than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector2f floor() {
+ this.x = Math.floor(x);
+ this.y = Math.floor(y);
+ return this;
+ }
+
+ public Vector2f floor(Vector2f dest) {
+ dest.x = Math.floor(x);
+ dest.y = Math.floor(y);
+ return dest;
+ }
+
+ /**
+ * Ceil each component of this vector
+ *
+ * @return this
+ */
+ public Vector2f ceil() {
+ this.x = Math.ceil(x);
+ this.y = Math.ceil(y);
+ return this;
+ }
+
+ public Vector2f ceil(Vector2f dest) {
+ dest.x = Math.ceil(x);
+ dest.y = Math.ceil(y);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the closest float that is equal to
+ * a mathematical integer, with ties rounding to positive infinity.
+ *
+ * @return this
+ */
+ public Vector2f round() {
+ this.x = Math.ceil(x);
+ this.y = Math.ceil(y);
+ return this;
+ }
+
+ public Vector2f round(Vector2f dest) {
+ dest.x = Math.round(x);
+ dest.y = Math.round(y);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y);
+ }
+
+ /**
+ * Set this
vector's components to their respective absolute values.
+ *
+ * @return this
+ */
+ public Vector2f absolute() {
+ this.x = Math.abs(this.x);
+ this.y = Math.abs(this.y);
+ return this;
+ }
+
+ public Vector2f absolute(Vector2f dest) {
+ dest.x = Math.abs(this.x);
+ dest.y = Math.abs(this.y);
+ return dest;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2fc.java
new file mode 100644
index 000000000..c106ddb4f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2fc.java
@@ -0,0 +1,609 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 2-dimensional vector of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector2fc {
+
+ /**
+ * @return the value of the x component
+ */
+ float x();
+
+ /**
+ * @return the value of the y component
+ */
+ float y();
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ * @see #get(int, FloatBuffer)
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector2fc getToAddress(long address);
+
+ /**
+ * Subtract v
from this
vector and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f sub(Vector2fc v, Vector2f dest);
+
+ /**
+ * Subtract (x, y)
from this vector and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f sub(float x, float y, Vector2f dest);
+
+ /**
+ * Return the dot product of this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ float dot(Vector2fc v);
+
+ /**
+ * Return the angle between this vector and the supplied vector.
+ *
+ * @param v
+ * the other vector
+ * @return the angle, in radians
+ */
+ float angle(Vector2fc v);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ float lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ float length();
+
+ /**
+ * Return the distance between this and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ float distance(Vector2fc v);
+
+ /**
+ * Return the distance squared between this and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance squared
+ */
+ float distanceSquared(Vector2fc v);
+
+ /**
+ * Return the distance between this
vector and (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the euclidean distance
+ */
+ float distance(float x, float y);
+
+ /**
+ * Return the distance squared between this
vector and (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the euclidean distance squared
+ */
+ float distanceSquared(float x, float y);
+
+ /**
+ * Normalize this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f normalize(Vector2f dest);
+
+ /**
+ * Scale this vector to have the given length and store the result in dest
.
+ *
+ * @param length
+ * the desired length
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f normalize(float length, Vector2f dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f add(Vector2fc v, Vector2f dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f add(float x, float y, Vector2f dest);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f negate(Vector2f dest);
+
+ /**
+ * Multiply the components of this vector by the given scalar and store the result in dest
.
+ *
+ * @param scalar
+ * the value to multiply this vector's components by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mul(float scalar, Vector2f dest);
+
+ /**
+ * Multiply the components of this Vector2f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mul(float x, float y, Vector2f dest);
+
+ /**
+ * Multiply this Vector2f component-wise by another Vector2f and store the result in dest
.
+ *
+ * @param v
+ * the vector to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mul(Vector2fc v, Vector2f dest);
+
+ /**
+ * Divide all components of this {@link Vector2f} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f div(float scalar, Vector2f dest);
+
+ /**
+ * Divide this Vector2f component-wise by another Vector2fc
+ * and store the result in dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f div(Vector2fc v, Vector2f dest);
+
+ /**
+ * Divide the components of this Vector2f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f div(float x, float y, Vector2f dest);
+
+ /**
+ * Multiply the given matrix with this Vector2f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mul(Matrix2fc mat, Vector2f dest);
+
+ /**
+ * Multiply the given matrix with this Vector2f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mul(Matrix2dc mat, Vector2f dest);
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mulTranspose(Matrix2fc mat, Vector2f dest);
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the z
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mulPosition(Matrix3x2fc mat, Vector2f dest);
+
+ /**
+ * Multiply the given 3x2 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the z
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f mulDirection(Matrix3x2fc mat, Vector2f dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f lerp(Vector2fc other, float t, Vector2f dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f fma(Vector2fc a, Vector2fc b, Vector2f dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f fma(float a, Vector2fc b, Vector2f dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f min(Vector2fc v, Vector2f dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f max(Vector2fc v, Vector2f dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..1]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..1]
+ */
+ int minComponent();
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..1]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..1]
+ */
+ float get(int component) throws IllegalArgumentException;
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector
+ * using the given {@link RoundingMode}.
+ *
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i get(int mode, Vector2i dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f get(Vector2f dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2d get(Vector2d dest);
+
+ /**
+ * Compute for each component of this vector the largest (closest to positive
+ * infinity) {@code float} value that is less than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f floor(Vector2f dest);
+
+ /**
+ * Compute for each component of this vector the smallest (closest to negative
+ * infinity) {@code float} value that is greater than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f ceil(Vector2f dest);
+
+ /**
+ * Compute for each component of this vector the closest float that is equal to
+ * a mathematical integer, with ties rounding to positive infinity and store
+ * the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f round(Vector2f dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2f absolute(Vector2f dest);
+
+ /**
+ * Compare the vector components of this
vector with the given vector using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param v
+ * the other vector
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the vector components are equal; false
otherwise
+ */
+ boolean equals(Vector2fc v, float delta);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(float x, float y);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2i.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2i.java
new file mode 100644
index 000000000..146ffd7e2
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2i.java
@@ -0,0 +1,965 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Represents a 2D vector with single-precision.
+ *
+ * @author RGreenlees
+ * @author Kai Burjack
+ * @author Hans Uhlig
+ */
+public class Vector2i implements Externalizable, Cloneable, Vector2ic {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public int x;
+ /**
+ * The y component of the vector.
+ */
+ public int y;
+
+ /**
+ * Create a new {@link Vector2i} and initialize its components to zero.
+ */
+ public Vector2i() {
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize both of its components with
+ * the given value.
+ *
+ * @param s
+ * the value of both components
+ */
+ public Vector2i(int s) {
+ this.x = s;
+ this.y = s;
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its components to the given values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ */
+ public Vector2i(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its component values and
+ * round using the given {@link RoundingMode}.
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector2i(float x, float y, int mode) {
+ this.x = Math.roundUsing(x, mode);
+ this.y = Math.roundUsing(y, mode);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its component values and
+ * round using the given {@link RoundingMode}.
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector2i(double x, double y, int mode) {
+ this.x = Math.roundUsing(x, mode);
+ this.y = Math.roundUsing(y, mode);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its components to the one of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ */
+ public Vector2i(Vector2ic v) {
+ x = v.x();
+ y = v.y();
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its components to the rounded value of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector2fc} to round and copy the values from
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector2i(Vector2fc v, int mode) {
+ x = Math.roundUsing(v.x(), mode);
+ y = Math.roundUsing(v.y(), mode);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its components to the rounded value of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector2dc} to round and copy the values from
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector2i(Vector2dc v, int mode) {
+ x = Math.roundUsing(v.x(), mode);
+ y = Math.roundUsing(v.y(), mode);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and initialize its two components from the first
+ * two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least three elements
+ */
+ public Vector2i(int[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ }
+
+ /**
+ * Create a new {@link Vector2i} and read this vector from the supplied
+ * {@link ByteBuffer} at the current buffer
+ * {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * read, use {@link #Vector2i(int, ByteBuffer)}, taking the absolute
+ * position as parameter.
+ *
+ * @see #Vector2i(int, ByteBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2i(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and read this vector from the supplied
+ * {@link ByteBuffer} starting at the specified absolute buffer
+ * position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2i(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and read this vector from the supplied
+ * {@link IntBuffer} at the current buffer
+ * {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * read, use {@link #Vector2i(int, IntBuffer)}, taking the absolute position
+ * as parameter.
+ *
+ * @see #Vector2i(int, IntBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2i(IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector2i} and read this vector from the supplied
+ * {@link IntBuffer} starting at the specified absolute buffer
+ * position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ */
+ public Vector2i(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public int x() {
+ return this.x;
+ }
+
+ public int y() {
+ return this.y;
+ }
+
+ /**
+ * Set the x and y components to the supplied value.
+ *
+ * @param s
+ * scalar value of both components
+ * @return this
+ */
+ public Vector2i set(int s) {
+ this.x = s;
+ this.y = s;
+ return this;
+ }
+
+ /**
+ * Set the x and y components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @return this
+ */
+ public Vector2i set(int x, int y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2i} to the values of v.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2i set(Vector2ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2i} to the values of v using {@link RoundingMode#TRUNCATE} rounding.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector2i set(Vector2dc v) {
+ this.x = (int) v.x();
+ this.y = (int) v.y();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2i} to the values of v using the given {@link RoundingMode}.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @return this
+ */
+ public Vector2i set(Vector2dc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector2i} to the values of v using the given {@link RoundingMode}.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @return this
+ */
+ public Vector2i set(Vector2fc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ return this;
+ }
+
+ /**
+ * Set the two components of this vector to the first two elements of the given array.
+ *
+ * @param xy
+ * the array containing at least two elements
+ * @return this
+ */
+ public Vector2i set(int[] xy) {
+ this.x = xy[0];
+ this.y = xy[1];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * read, use {@link #set(int, ByteBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #set(int, ByteBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2i set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2i set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link IntBuffer} at the current
+ * buffer {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * read, use {@link #set(int, IntBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #set(int, IntBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2i set(IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link IntBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * values will be read in x, y
order
+ * @return this
+ */
+ public Vector2i set(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 2 integer values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector2i setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ public int get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..1]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..1]
+ */
+ public Vector2i setComponent(int component, int value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public IntBuffer get(IntBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public IntBuffer get(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector2ic getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one and store the result in
+ * this
.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector2i sub(Vector2ic v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ return this;
+ }
+
+ public Vector2i sub(Vector2ic v, Vector2i dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ return dest;
+ }
+
+ /**
+ * Decrement the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @return this
+ */
+ public Vector2i sub(int x, int y) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ return this;
+ }
+
+ public Vector2i sub(int x, int y, Vector2i dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ return dest;
+ }
+
+ public long lengthSquared() {
+ return x * x + y * y;
+ }
+
+ /**
+ * Get the length squared of a 2-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ *
+ * @return the length squared of the given vector
+ */
+ public static long lengthSquared(int x, int y) {
+ return x * x + y * y;
+ }
+
+ public double length() {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ /**
+ * Get the length of a 2-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ *
+ * @return the length squared of the given vector
+ */
+ public static double length(int x, int y) {
+ return Math.sqrt(x * x + y * y);
+ }
+
+ public double distance(Vector2ic v) {
+ int dx = this.x - v.x();
+ int dy = this.y - v.y();
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public double distance(int x, int y) {
+ int dx = this.x - x;
+ int dy = this.y - y;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public long distanceSquared(Vector2ic v) {
+ int dx = this.x - v.x();
+ int dy = this.y - v.y();
+ return dx * dx + dy * dy;
+ }
+
+ public long distanceSquared(int x, int y) {
+ int dx = this.x - x;
+ int dy = this.y - y;
+ return dx * dx + dy * dy;
+ }
+
+ public long gridDistance(Vector2ic v) {
+ return Math.abs(v.x() - x()) + Math.abs(v.y() - y());
+ }
+
+ public long gridDistance(int x, int y) {
+ return Math.abs(x - x()) + Math.abs(y - y());
+ }
+
+ /**
+ * Return the distance between (x1, y1)
and (x2, y2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @return the euclidean distance
+ */
+ public static double distance(int x1, int y1, int x2, int y2) {
+ int dx = x1 - x2;
+ int dy = y1 - y2;
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ /**
+ * Return the squared distance between (x1, y1)
and (x2, y2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static long distanceSquared(int x1, int y1, int x2, int y2) {
+ int dx = x1 - x2;
+ int dy = y1 - y2;
+ return dx * dx + dy * dy;
+ }
+
+ /**
+ * Add v
to this vector.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector2i add(Vector2ic v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ return this;
+ }
+
+ public Vector2i add(Vector2ic v, Vector2i dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @return this
+ */
+ public Vector2i add(int x, int y) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ return this;
+ }
+
+ public Vector2i add(int x, int y, Vector2i dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ return dest;
+ }
+
+ /**
+ * Multiply all components of this {@link Vector2i} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to multiply this vector by
+ * @return this
+ */
+ public Vector2i mul(int scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ return this;
+ }
+
+ public Vector2i mul(int scalar, Vector2i dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector by this one.
+ *
+ * @param v
+ * the vector to multiply
+ * @return this
+ */
+ public Vector2i mul(Vector2ic v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ return this;
+ }
+
+ public Vector2i mul(Vector2ic v, Vector2i dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to multiply
+ * @param y
+ * the y component to multiply
+ * @return this
+ */
+ public Vector2i mul(int x, int y) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ return this;
+ }
+
+ public Vector2i mul(int x, int y, Vector2i dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector2i} by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return a vector holding the result
+ */
+ public Vector2i div(float scalar) {
+ float invscalar = 1.0f / scalar;
+ this.x = (int) (x * invscalar);
+ this.y = (int) (y * invscalar);
+ return this;
+ }
+
+ public Vector2i div(float scalar, Vector2i dest) {
+ float invscalar = 1.0f / scalar;
+ dest.x = (int) (x * invscalar);
+ dest.y = (int) (y * invscalar);
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector2i} by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return a vector holding the result
+ */
+ public Vector2i div(int scalar) {
+ this.x = x / scalar;
+ this.y = y / scalar;
+ return this;
+ }
+
+ public Vector2i div(int scalar, Vector2i dest) {
+ dest.x = x / scalar;
+ dest.y = y / scalar;
+ return dest;
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector2i zero() {
+ this.x = 0;
+ this.y = 0;
+ return this;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(x);
+ out.writeInt(y);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ x = in.readInt();
+ y = in.readInt();
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector2i negate() {
+ this.x = -x;
+ this.y = -y;
+ return this;
+ }
+
+ public Vector2i negate(Vector2i dest) {
+ dest.x = -x;
+ dest.y = -y;
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector2i min(Vector2ic v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ return this;
+ }
+
+ public Vector2i min(Vector2ic v, Vector2i dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector2i max(Vector2ic v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ return this;
+ }
+
+ public Vector2i max(Vector2ic v, Vector2i dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ return dest;
+ }
+
+ public int maxComponent() {
+ int absX = Math.abs(x);
+ int absY = Math.abs(y);
+ if (absX >= absY)
+ return 0;
+ return 1;
+ }
+
+ public int minComponent() {
+ int absX = Math.abs(x);
+ int absY = Math.abs(y);
+ if (absX < absY)
+ return 0;
+ return 1;
+ }
+
+ /**
+ * Set this
vector's components to their respective absolute values.
+ *
+ * @return this
+ */
+ public Vector2i absolute() {
+ this.x = Math.abs(this.x);
+ this.y = Math.abs(this.y);
+ return this;
+ }
+
+ public Vector2i absolute(Vector2i dest) {
+ dest.x = Math.abs(this.x);
+ dest.y = Math.abs(this.y);
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + x;
+ result = prime * result + y;
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Vector2i other = (Vector2i) obj;
+ if (x != other.x) {
+ return false;
+ }
+ if (y != other.y) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean equals(int x, int y) {
+ if (this.x != x)
+ return false;
+ if (this.y != y)
+ return false;
+ return true;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + formatter.format(x) + " " + formatter.format(y) + ")";
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2ic.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2ic.java
new file mode 100644
index 000000000..949e3f698
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector2ic.java
@@ -0,0 +1,391 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Interface to a read-only view of a 2-dimensional vector of integers.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector2ic {
+
+ /**
+ * @return the value of the x component
+ */
+ int x();
+
+ /**
+ * @return the value of the y component
+ */
+ int y();
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * stored, use {@link #get(int, ByteBuffer)}, taking the absolute position
+ * as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link IntBuffer} at the current
+ * buffer {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * stored, use {@link #get(int, IntBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #get(int, IntBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ IntBuffer get(IntBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link IntBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y
order
+ * @return the passed in buffer
+ */
+ IntBuffer get(int index, IntBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector2ic getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i sub(Vector2ic v, Vector2i dest);
+
+ /**
+ * Decrement the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i sub(int x, int y, Vector2i dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ long lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ double length();
+
+ /**
+ * Return the distance between this Vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector2ic v);
+
+ /**
+ * Return the distance between this
vector and (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the euclidean distance
+ */
+ double distance(int x, int y);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ long distanceSquared(Vector2ic v);
+
+ /**
+ * Return the square of the distance between this
vector and
+ * (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the square of the distance
+ */
+ long distanceSquared(int x, int y);
+
+ /**
+ * Return the grid distance in between (aka 1-Norm, Minkowski or Manhattan distance)
+ * (x, y)
.
+ *
+ * @param v
+ * the other vector
+ * @return the grid distance
+ */
+ long gridDistance(Vector2ic v);
+
+ /**
+ * Return the grid distance in between (aka 1-Norm, Minkowski or Manhattan distance)
+ * (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @return the grid distance
+ */
+ long gridDistance(int x, int y);
+
+ /**
+ * Add the supplied vector to this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i add(Vector2ic v, Vector2i dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i add(int x, int y, Vector2i dest);
+
+ /**
+ * Multiply all components of this {@link Vector2ic} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i mul(int scalar, Vector2i dest);
+
+ /**
+ * Multiply the supplied vector by this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to multiply
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i mul(Vector2ic v, Vector2i dest);
+
+ /**
+ * Multiply the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to multiply
+ * @param y
+ * the y component to multiply
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i mul(int x, int y, Vector2i dest);
+
+ /**
+ * Divide all components of this {@link Vector2i} by the given scalar value
+ * and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i div(float scalar, Vector2i dest);
+
+ /**
+ * Divide all components of this {@link Vector2i} by the given scalar value
+ * and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i div(int scalar, Vector2i dest);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i negate(Vector2i dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i min(Vector2ic v, Vector2i dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i max(Vector2ic v, Vector2i dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..1]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..1]
+ */
+ int minComponent();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector2i absolute(Vector2i dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..1]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..1]
+ */
+ int get(int component) throws IllegalArgumentException;
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(int x, int y);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3d.java
new file mode 100644
index 000000000..9a00440d0
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3d.java
@@ -0,0 +1,2613 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.*;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a Vector comprising 3 doubles and associated
+ * transformations.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ * @author F. Neurath
+ */
+public class Vector3d implements Externalizable, Cloneable, Vector3dc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public double x;
+ /**
+ * The y component of the vector.
+ */
+ public double y;
+ /**
+ * The z component of the vector.
+ */
+ public double z;
+
+ /**
+ * Create a new {@link Vector3d} with all components set to zero.
+ */
+ public Vector3d() {
+ }
+
+ /**
+ * Create a new {@link Vector3d} and initialize all three components with the given value.
+ *
+ * @param d
+ * the value of all three components
+ */
+ public Vector3d(double d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ }
+
+ /**
+ * Create a new {@link Vector3d} with the given component values.
+ *
+ * @param x
+ * the value of x
+ * @param y
+ * the value of y
+ * @param z
+ * the value of z
+ */
+ public Vector3d(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3d} whose values will be copied from the given vector.
+ *
+ * @param v
+ * provides the initial values for the new vector
+ */
+ public Vector3d(Vector3fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ }
+
+ /**
+ * Create a new {@link Vector3d} whose values will be copied from the given vector.
+ *
+ * @param v
+ * provides the initial values for the new vector
+ */
+ public Vector3d(Vector3ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ }
+
+ /**
+ * Create a new {@link Vector3d} with the first two components from the
+ * given v
and the given z
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ * @param z
+ * the z component
+ */
+ public Vector3d(Vector2fc v, double z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3d} with the first two components from the
+ * given v
and the given z
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ * @param z
+ * the z component
+ */
+ public Vector3d(Vector2ic v, double z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3d} whose values will be copied from the given vector.
+ *
+ * @param v
+ * provides the initial values for the new vector
+ */
+ public Vector3d(Vector3dc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ }
+
+ /**
+ * Create a new {@link Vector3d} with the first two components from the
+ * given v
and the given z
+ *
+ * @param v
+ * the {@link Vector2d} to copy the values from
+ * @param z
+ * the z component
+ */
+ public Vector3d(Vector2dc v, double z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3d} and initialize its three components from the first
+ * three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ */
+ public Vector3d(double[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ }
+
+ /**
+ * Create a new {@link Vector3d} and initialize its three components from the first
+ * three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ */
+ public Vector3d(float[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ }
+
+ /**
+ * Create a new {@link Vector3d} and read this vector from the supplied {@link ByteBuffer}
+ * at the current buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #Vector3d(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer values will be read in x, y, z
order
+ * @see #Vector3d(int, ByteBuffer)
+ */
+ public Vector3d(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3d} and read this vector from the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index the absolute position into the ByteBuffer
+ * @param buffer values will be read in x, y, z
order
+ */
+ public Vector3d(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3d} and read this vector from the supplied {@link DoubleBuffer}
+ * at the current buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is read, use {@link #Vector3d(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer values will be read in x, y, z
order
+ * @see #Vector3d(int, DoubleBuffer)
+ */
+ public Vector3d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3d} and read this vector from the supplied {@link DoubleBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index the absolute position into the DoubleBuffer
+ * @param buffer values will be read in x, y, z
order
+ */
+ public Vector3d(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public double x() {
+ return this.x;
+ }
+
+ public double y() {
+ return this.y;
+ }
+
+ public double z() {
+ return this.z;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * @param v
+ * the vector to set this vector's components from
+ * @return this
+ */
+ public Vector3d set(Vector3dc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * @param v
+ * the vector to set this vector's components from
+ * @return this
+ */
+ public Vector3d set(Vector3ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
+ * and the z component from the given z
+ *
+ * @param v
+ * the {@link Vector2dc} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3d set(Vector2dc v, double z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
+ * and the z component from the given z
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3d set(Vector2ic v, double z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * @param v
+ * the vector to set this vector's components from
+ * @return this
+ */
+ public Vector3d set(Vector3fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
+ * and the z component from the given z
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3d set(Vector2fc v, double z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components to the supplied value.
+ *
+ * @param d
+ * the value of all three components
+ * @return this
+ */
+ public Vector3d set(double d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3d set(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the three components of this vector to the first three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ * @return this
+ */
+ public Vector3d set(double[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ return this;
+ }
+
+ /**
+ * Set the three components of this vector to the first three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ * @return this
+ */
+ public Vector3d set(float[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #set(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ * @see #set(int, ByteBuffer)
+ */
+ public Vector3d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is read, use {@link #set(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ * @see #set(int, DoubleBuffer)
+ */
+ public Vector3d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 3 double values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector3d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..2]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..2]
+ */
+ public Vector3d setComponent(int component, double value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getf(ByteBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getf(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector3dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one.
+ *
+ * @param v
+ * the vector to subtract from this
+ * @return this
+ */
+ public Vector3d sub(Vector3dc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ this.z = z - v.z();
+ return this;
+ }
+
+ public Vector3d sub(Vector3dc v, Vector3d dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ dest.z = z - v.z();
+ return dest;
+ }
+
+ /**
+ * Subtract the supplied vector from this one.
+ *
+ * @param v
+ * the vector to subtract from this
+ * @return this
+ */
+ public Vector3d sub(Vector3fc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ this.z = z - v.z();
+ return this;
+ }
+
+ public Vector3d sub(Vector3fc v, Vector3d dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ dest.z = z - v.z();
+ return dest;
+ }
+
+ /**
+ * Subtract (x, y, z)
from this vector.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @return this
+ */
+ public Vector3d sub(double x, double y, double z) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ this.z = this.z - z;
+ return this;
+ }
+
+ public Vector3d sub(double x, double y, double z, Vector3d dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ dest.z = this.z - z;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector3d add(Vector3dc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ this.z = z + v.z();
+ return this;
+ }
+
+ public Vector3d add(Vector3dc v, Vector3d dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ dest.z = z + v.z();
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector3d add(Vector3fc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ this.z = z + v.z();
+ return this;
+ }
+
+ public Vector3d add(Vector3fc v, Vector3d dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ dest.z = z + v.z();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @return this
+ */
+ public Vector3d add(double x, double y, double z) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.z = this.z + z;
+ return this;
+ }
+
+ public Vector3d add(double x, double y, double z, Vector3d dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector3d fma(Vector3dc a, Vector3dc b) {
+ this.x = Math.fma(a.x(), b.x(), x);
+ this.y = Math.fma(a.y(), b.y(), y);
+ this.z = Math.fma(a.z(), b.z(), z);
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector3d fma(double a, Vector3dc b) {
+ this.x = Math.fma(a, b.x(), x);
+ this.y = Math.fma(a, b.y(), y);
+ this.z = Math.fma(a, b.z(), z);
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector3d fma(Vector3fc a, Vector3fc b) {
+ this.x = Math.fma(a.x(), b.x(), x);
+ this.y = Math.fma(a.y(), b.y(), y);
+ this.z = Math.fma(a.z(), b.z(), z);
+ return this;
+ }
+
+ public Vector3d fma(Vector3fc a, Vector3fc b, Vector3d dest) {
+ dest.x = Math.fma(a.x(), b.x(), x);
+ dest.y = Math.fma(a.y(), b.y(), y);
+ dest.z = Math.fma(a.z(), b.z(), z);
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector3d fma(double a, Vector3fc b) {
+ this.x = Math.fma(a, b.x(), x);
+ this.y = Math.fma(a, b.y(), y);
+ this.z = Math.fma(a, b.z(), z);
+ return this;
+ }
+
+ public Vector3d fma(Vector3dc a, Vector3dc b, Vector3d dest) {
+ dest.x = Math.fma(a.x(), b.x(), x);
+ dest.y = Math.fma(a.y(), b.y(), y);
+ dest.z = Math.fma(a.z(), b.z(), z);
+ return dest;
+ }
+
+ public Vector3d fma(double a, Vector3dc b, Vector3d dest) {
+ dest.x = Math.fma(a, b.x(), x);
+ dest.y = Math.fma(a, b.y(), y);
+ dest.z = Math.fma(a, b.z(), z);
+ return dest;
+ }
+
+ public Vector3d fma(Vector3dc a, Vector3fc b, Vector3d dest) {
+ dest.x = Math.fma(a.x(), b.x(), x);
+ dest.y = Math.fma(a.y(), b.y(), y);
+ dest.z = Math.fma(a.z(), b.z(), z);
+ return dest;
+ }
+
+ public Vector3d fma(double a, Vector3fc b, Vector3d dest) {
+ dest.x = Math.fma(a, b.x(), x);
+ dest.y = Math.fma(a, b.y(), y);
+ dest.z = Math.fma(a, b.z(), z);
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector3d mulAdd(Vector3dc a, Vector3dc b) {
+ this.x = Math.fma(x, a.x(), b.x());
+ this.y = Math.fma(y, a.y(), b.y());
+ this.z = Math.fma(z, a.z(), b.z());
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector3d mulAdd(double a, Vector3dc b) {
+ this.x = Math.fma(x, a, b.x());
+ this.y = Math.fma(y, a, b.y());
+ this.z = Math.fma(z, a, b.z());
+ return this;
+ }
+
+ public Vector3d mulAdd(Vector3dc a, Vector3dc b, Vector3d dest) {
+ dest.x = Math.fma(x, a.x(), b.x());
+ dest.y = Math.fma(y, a.y(), b.y());
+ dest.z = Math.fma(z, a.z(), b.z());
+ return dest;
+ }
+
+ public Vector3d mulAdd(double a, Vector3dc b, Vector3d dest) {
+ dest.x = Math.fma(x, a, b.x());
+ dest.y = Math.fma(y, a, b.y());
+ dest.z = Math.fma(z, a, b.z());
+ return dest;
+ }
+
+ public Vector3d mulAdd(Vector3fc a, Vector3dc b, Vector3d dest) {
+ dest.x = Math.fma(x, a.x(), b.x());
+ dest.y = Math.fma(y, a.y(), b.y());
+ dest.z = Math.fma(z, a.z(), b.z());
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector3d component-wise by another Vector3dc.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector3d mul(Vector3dc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ return this;
+ }
+
+ /**
+ * Multiply this Vector3d component-wise by another Vector3fc.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector3d mul(Vector3fc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ return this;
+ }
+
+ public Vector3d mul(Vector3fc v, Vector3d dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ return dest;
+ }
+
+ public Vector3d mul(Vector3dc v, Vector3d dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ return dest;
+ }
+
+ /**
+ * Divide this Vector3d component-wise by another Vector3dc.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector3d div(Vector3d v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ this.z = z / v.z();
+ return this;
+ }
+
+ /**
+ * Divide this Vector3d component-wise by another Vector3fc.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector3d div(Vector3fc v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ this.z = z / v.z();
+ return this;
+ }
+
+ public Vector3d div(Vector3fc v, Vector3d dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ dest.z = z / v.z();
+ return dest;
+ }
+
+ public Vector3d div(Vector3dc v, Vector3d dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ dest.z = z / v.z();
+ return dest;
+ }
+
+ public Vector3d mulProject(Matrix4dc mat, double w, Vector3d dest) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulProject(Matrix4dc mat, Vector3d dest) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30()))) * invW;
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31()))) * invW;
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32()))) * invW;
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
this Vector3d, perform perspective division.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulProject(Matrix4dc mat) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30()))) * invW;
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31()))) * invW;
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32()))) * invW;
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulProject(Matrix4fc mat, Vector3d dest) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = (mat.m00() * x + mat.m10() * y + mat.m20() * z + mat.m30()) * invW;
+ double ry = (mat.m01() * x + mat.m11() * y + mat.m21() * z + mat.m31()) * invW;
+ double rz = (mat.m02() * x + mat.m12() * y + mat.m22() * z + mat.m32()) * invW;
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector3d, perform perspective division.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulProject(Matrix4fc mat) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = (mat.m00() * x + mat.m10() * y + mat.m20() * z + mat.m30()) * invW;
+ double ry = (mat.m01() * x + mat.m11() * y + mat.m21() * z + mat.m31()) * invW;
+ double rz = (mat.m02() * x + mat.m12() * y + mat.m22() * z + mat.m32()) * invW;
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector3d.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mul(Matrix3fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector3d.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mul(Matrix3dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mul(Matrix3dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3f mul(Matrix3dc mat, Vector3f dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = (float) rx;
+ dest.y = (float) ry;
+ dest.z = (float) rz;
+ return dest;
+ }
+
+ public Vector3d mul(Matrix3fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector3d by assuming a third row in the matrix of (0, 0, 1)
+ * and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3d mul(Matrix3x2dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector3d mul(Matrix3x2dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector3d by assuming a third row in the matrix of (0, 0, 1)
+ * and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3d mul(Matrix3x2fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ this.x = rx;
+ this.y = ry;
+ return this;
+ }
+
+ public Vector3d mul(Matrix3x2fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3d and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3d mulTranspose(Matrix3dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulTranspose(Matrix3dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3d and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3d mulTranspose(Matrix3fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulTranspose(Matrix3fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulPosition(Matrix4fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulPosition(Matrix4dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulPosition(Matrix4x3dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulPosition(Matrix4x3fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulPosition(Matrix4dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulPosition(Matrix4fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulPosition(Matrix4x3dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulPosition(Matrix4x3fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulTransposePosition(Matrix4dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03())));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13())));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulTransposePosition(Matrix4dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03())));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13())));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulTransposePosition(Matrix4fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03())));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13())));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulTransposePosition(Matrix4fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03())));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13())));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and return the w component
+ * of the resulting 4D vector.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return the w component of the resulting 4D vector after multiplication
+ */
+ public double mulPositionW(Matrix4fc mat) {
+ double w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return w;
+ }
+
+ public double mulPositionW(Matrix4fc mat, Vector3d dest) {
+ double w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return w;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and return the w component
+ * of the resulting 4D vector.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return the w component of the resulting 4D vector after multiplication
+ */
+ public double mulPositionW(Matrix4dc mat) {
+ double w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return w;
+ }
+
+ public double mulPositionW(Matrix4dc mat, Vector3d dest) {
+ double w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return w;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulDirection(Matrix4fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulDirection(Matrix4dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulDirection(Matrix4x3dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulDirection(Matrix4x3fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulDirection(Matrix4dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulDirection(Matrix4fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulDirection(Matrix4x3dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d mulDirection(Matrix4x3fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulTransposeDirection(Matrix4dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulTransposeDirection(Matrix4dc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @return this
+ */
+ public Vector3d mulTransposeDirection(Matrix4fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d mulTransposeDirection(Matrix4fc mat, Vector3d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ double ry = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ double rz = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector3d by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to multiply this vector by
+ * @return this
+ */
+ public Vector3d mul(double scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ this.z = z * scalar;
+ return this;
+ }
+
+ public Vector3d mul(double scalar, Vector3d dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ dest.z = z * scalar;
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this Vector3d by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @param z
+ * the z component to multiply this vector by
+ * @return this
+ */
+ public Vector3d mul(double x, double y, double z) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ this.z = this.z * z;
+ return this;
+ }
+
+ public Vector3d mul(double x, double y, double z, Vector3d dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ dest.z = this.z * z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector by the given quaternion quat
and store the result in this
.
+ *
+ * @see Quaterniond#transform(Vector3d)
+ *
+ * @param quat
+ * the quaternion to rotate this vector
+ * @return this
+ */
+ public Vector3d rotate(Quaterniondc quat) {
+ return quat.transform(this, this);
+ }
+
+ public Vector3d rotate(Quaterniondc quat, Vector3d dest) {
+ return quat.transform(this, dest);
+ }
+
+ public Quaterniond rotationTo(Vector3dc toDir, Quaterniond dest) {
+ return dest.rotationTo(this, toDir);
+ }
+
+ public Quaterniond rotationTo(double toDirX, double toDirY, double toDirZ, Quaterniond dest) {
+ return dest.rotationTo(x, y, z, toDirX, toDirY, toDirZ);
+ }
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x component of the rotation axis
+ * @param y
+ * the y component of the rotation axis
+ * @param z
+ * the z component of the rotation axis
+ * @return this
+ */
+ public Vector3d rotateAxis(double angle, double x, double y, double z) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateX(x * angle, this);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateY(y * angle, this);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateZ(z * angle, this);
+ return rotateAxisInternal(angle, x, y, z, this);
+ }
+
+ public Vector3d rotateAxis(double angle, double aX, double aY, double aZ, Vector3d dest) {
+ if (aY == 0.0 && aZ == 0.0 && Math.absEqualsOne(aX))
+ return rotateX(aX * angle, dest);
+ else if (aX == 0.0 && aZ == 0.0 && Math.absEqualsOne(aY))
+ return rotateY(aY * angle, dest);
+ else if (aX == 0.0 && aY == 0.0 && Math.absEqualsOne(aZ))
+ return rotateZ(aZ * angle, dest);
+ return rotateAxisInternal(angle, aX, aY, aZ, dest);
+ }
+
+ private Vector3d rotateAxisInternal(double angle, double aX, double aY, double aZ, Vector3d dest) {
+ double hangle = angle * 0.5;
+ double sinAngle = Math.sin(hangle);
+ double qx = aX * sinAngle, qy = aY * sinAngle, qz = aZ * sinAngle;
+ double qw = Math.cosFromSin(sinAngle, hangle);
+ double w2 = qw * qw, x2 = qx * qx, y2 = qy * qy, z2 = qz * qz, zw = qz * qw;
+ double xy = qx * qy, xz = qx * qz, yw = qy * qw, yz = qy * qz, xw = qx * qw;
+ double nx = (w2 + x2 - z2 - y2) * x + (-zw + xy - zw + xy) * y + (yw + xz + xz + yw) * z;
+ double ny = (xy + zw + zw + xy) * x + ( y2 - z2 + w2 - x2) * y + (yz + yz - xw - xw) * z;
+ double nz = (xz - yw + xz - yw) * x + ( yz + yz + xw + xw) * y + (z2 - y2 - x2 + w2) * z;
+ dest.x = nx;
+ dest.y = ny;
+ dest.z = nz;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the X axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector3d rotateX(double angle) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double y = this.y * cos - this.z * sin;
+ double z = this.y * sin + this.z * cos;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ public Vector3d rotateX(double angle, Vector3d dest) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double y = this.y * cos - this.z * sin;
+ double z = this.y * sin + this.z * cos;
+ dest.x = this.x;
+ dest.y = y;
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Y axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector3d rotateY(double angle) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos + this.z * sin;
+ double z = -this.x * sin + this.z * cos;
+ this.x = x;
+ this.z = z;
+ return this;
+ }
+
+ public Vector3d rotateY(double angle, Vector3d dest) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos + this.z * sin;
+ double z = -this.x * sin + this.z * cos;
+ dest.x = x;
+ dest.y = this.y;
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Z axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector3d rotateZ(double angle) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos - this.y * sin;
+ double y = this.x * sin + this.y * cos;
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ public Vector3d rotateZ(double angle, Vector3d dest) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos - this.y * sin;
+ double y = this.x * sin + this.y * cos;
+ dest.x = x;
+ dest.y = y;
+ dest.z = this.z;
+ return dest;
+ }
+
+ /**
+ * Divide this Vector3d by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide this vector by
+ * @return this
+ */
+ public Vector3d div(double scalar) {
+ double inv = 1.0 / scalar;
+ this.x = x * inv;
+ this.y = y * inv;
+ this.z = z * inv;
+ return this;
+ }
+
+ public Vector3d div(double scalar, Vector3d dest) {
+ double inv = 1.0 / scalar;
+ dest.x = x * inv;
+ dest.y = y * inv;
+ dest.z = z * inv;
+ return dest;
+ }
+
+ /**
+ * Divide the components of this Vector3d by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @param z
+ * the z component to divide this vector by
+ * @return this
+ */
+ public Vector3d div(double x, double y, double z) {
+ this.x = this.x / x;
+ this.y = this.y / y;
+ this.z = this.z / z;
+ return this;
+ }
+
+ public Vector3d div(double x, double y, double z, Vector3d dest) {
+ dest.x = this.x / x;
+ dest.y = this.y / y;
+ dest.z = this.z / z;
+ return dest;
+ }
+
+ public double lengthSquared() {
+ return Math.fma(x, x, Math.fma(y, y, z * z));
+ }
+
+ /**
+ * Get the length squared of a 3-dimensional double-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ *
+ * @return the length squared of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static double lengthSquared(double x, double y, double z) {
+ return Math.fma(x, x, Math.fma(y, y, z * z));
+ }
+
+ public double length() {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ }
+
+ /**
+ * Get the length of a 3-dimensional double-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ *
+ * @return the length of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static double length(double x, double y, double z) {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ }
+
+ /**
+ * Normalize this vector.
+ *
+ * @return this
+ */
+ public Vector3d normalize() {
+ double invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ return this;
+ }
+
+ public Vector3d normalize(Vector3d dest) {
+ double invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ return dest;
+ }
+
+ /**
+ * Scale this vector to have the given length.
+ *
+ * @param length
+ * the desired length
+ * @return this
+ */
+ public Vector3d normalize(double length) {
+ double invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z))) * length;
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ return this;
+ }
+
+ public Vector3d normalize(double length, Vector3d dest) {
+ double invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z))) * length;
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ return dest;
+ }
+
+ /**
+ * Set this vector to be the cross product of this and v2.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3d cross(Vector3dc v) {
+ double rx = Math.fma(y, v.z(), -z * v.y());
+ double ry = Math.fma(z, v.x(), -x * v.z());
+ double rz = Math.fma(x, v.y(), -y * v.x());
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Set this vector to be the cross product of itself and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return this
+ */
+ public Vector3d cross(double x, double y, double z) {
+ double rx = Math.fma(this.y, z, -this.z * y);
+ double ry = Math.fma(this.z, x, -this.x * z);
+ double rz = Math.fma(this.x, y, -this.y * x);
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3d cross(Vector3dc v, Vector3d dest) {
+ double rx = Math.fma(y, v.z(), -z * v.y());
+ double ry = Math.fma(z, v.x(), -x * v.z());
+ double rz = Math.fma(x, v.y(), -y * v.x());
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3d cross(double x, double y, double z, Vector3d dest) {
+ double rx = Math.fma(this.y, z, -this.z * y);
+ double ry = Math.fma(this.z, x, -this.x * z);
+ double rz = Math.fma(this.x, y, -this.y * x);
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public double distance(Vector3dc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ double dz = this.z - v.z();
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)));
+ }
+
+ public double distance(double x, double y, double z) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ double dz = this.z - z;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)));
+ }
+
+ public double distanceSquared(Vector3dc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ double dz = this.z - v.z();
+ return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz));
+ }
+
+ public double distanceSquared(double x, double y, double z) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ double dz = this.z - z;
+ return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz));
+ }
+
+ /**
+ * Return the distance between (x1, y1, z1)
and (x2, y2, z2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @return the euclidean distance
+ */
+ public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) {
+ return Math.sqrt(distanceSquared(x1, y1, z1, x2, y2, z2));
+ }
+
+ /**
+ * Return the squared distance between (x1, y1, z1)
and (x2, y2, z2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static double distanceSquared(double x1, double y1, double z1, double x2, double y2, double z2) {
+ double dx = x1 - x2;
+ double dy = y1 - y2;
+ double dz = z1 - z2;
+ return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz));
+ }
+
+ public double dot(Vector3dc v) {
+ return Math.fma(this.x, v.x(), Math.fma(this.y, v.y(), this.z * v.z()));
+ }
+
+ public double dot(double x, double y, double z) {
+ return Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ }
+
+ public double angleCos(Vector3dc v) {
+ double length1Squared = Math.fma(x, x, Math.fma(y, y, z * z));
+ double length2Squared = Math.fma(v.x(), v.x(), Math.fma(v.y(), v.y(), v.z() * v.z()));
+ double dot = Math.fma(x, v.x(), Math.fma(y, v.y(), z * v.z()));
+ return dot / Math.sqrt(length1Squared * length2Squared);
+ }
+
+ public double angle(Vector3dc v) {
+ double cos = angleCos(v);
+ // This is because sometimes cos goes above 1 or below -1 because of lost precision
+ cos = cos < 1 ? cos : 1;
+ cos = cos > -1 ? cos : -1;
+ return Math.acos(cos);
+ }
+
+ public double angleSigned(Vector3dc v, Vector3dc n) {
+ double x = v.x();
+ double y = v.y();
+ double z = v.z();
+ return Math.atan2(
+ (this.y * z - this.z * y) * n.x() + (this.z * x - this.x * z) * n.y() + (this.x * y - this.y * x) * n.z(),
+ this.x * x + this.y * y + this.z * z);
+ }
+
+ public double angleSigned(double x, double y, double z, double nx, double ny, double nz) {
+ return Math.atan2(
+ (this.y * z - this.z * y) * nx + (this.z * x - this.x * z) * ny + (this.x * y - this.y * x) * nz,
+ this.x * x + this.y * y + this.z * z);
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3d min(Vector3dc v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ this.z = z < v.z() ? z : v.z();
+ return this;
+ }
+
+ public Vector3d min(Vector3dc v, Vector3d dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ dest.z = z < v.z() ? z : v.z();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3d max(Vector3dc v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ this.z = z > v.z() ? z : v.z();
+ return this;
+ }
+
+ public Vector3d max(Vector3dc v, Vector3d dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ dest.z = z > v.z() ? z : v.z();
+ return dest;
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector3d zero() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ return this;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + " " + Runtime.format(z, formatter) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(x);
+ out.writeDouble(y);
+ out.writeDouble(z);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ x = in.readDouble();
+ y = in.readDouble();
+ z = in.readDouble();
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector3d negate() {
+ this.x = -x;
+ this.y = -y;
+ this.z = -z;
+ return this;
+ }
+
+ public Vector3d negate(Vector3d dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ return dest;
+ }
+
+ /**
+ * Set this
vector's components to their respective absolute values.
+ *
+ * @return this
+ */
+ public Vector3d absolute() {
+ this.x = Math.abs(this.x);
+ this.y = Math.abs(this.y);
+ this.z = Math.abs(this.z);
+ return this;
+ }
+
+ public Vector3d absolute(Vector3d dest) {
+ dest.x = Math.abs(this.x);
+ dest.y = Math.abs(this.y);
+ dest.z = Math.abs(this.z);
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(x);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(y);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(z);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Vector3d other = (Vector3d) obj;
+ if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
+ return false;
+ if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
+ return false;
+ if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Vector3dc v, double delta) {
+ if (this == v)
+ return true;
+ if (v == null)
+ return false;
+ if (!(v instanceof Vector3dc))
+ return false;
+ if (!Runtime.equals(x, v.x(), delta))
+ return false;
+ if (!Runtime.equals(y, v.y(), delta))
+ return false;
+ if (!Runtime.equals(z, v.z(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(double x, double y, double z) {
+ if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(x))
+ return false;
+ if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(y))
+ return false;
+ if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(z))
+ return false;
+ return true;
+ }
+
+ /**
+ * Reflect this vector about the given normal vector.
+ *
+ * @param normal
+ * the vector to reflect about
+ * @return this
+ */
+ public Vector3d reflect(Vector3dc normal) {
+ double x = normal.x();
+ double y = normal.y();
+ double z = normal.z();
+ double dot = Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ this.x = this.x - (dot + dot) * x;
+ this.y = this.y - (dot + dot) * y;
+ this.z = this.z - (dot + dot) * z;
+ return this;
+ }
+
+ /**
+ * Reflect this vector about the given normal vector.
+ *
+ * @param x
+ * the x component of the normal
+ * @param y
+ * the y component of the normal
+ * @param z
+ * the z component of the normal
+ * @return this
+ */
+ public Vector3d reflect(double x, double y, double z) {
+ double dot = Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ this.x = this.x - (dot + dot) * x;
+ this.y = this.y - (dot + dot) * y;
+ this.z = this.z - (dot + dot) * z;
+ return this;
+ }
+
+ public Vector3d reflect(Vector3dc normal, Vector3d dest) {
+ double x = normal.x();
+ double y = normal.y();
+ double z = normal.z();
+ double dot = Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ dest.x = this.x - (dot + dot) * x;
+ dest.y = this.y - (dot + dot) * y;
+ dest.z = this.z - (dot + dot) * z;
+ return dest;
+ }
+
+ public Vector3d reflect(double x, double y, double z, Vector3d dest) {
+ double dot = Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ dest.x = this.x - (dot + dot) * x;
+ dest.y = this.y - (dot + dot) * y;
+ dest.z = this.z - (dot + dot) * z;
+ return dest;
+ }
+
+ /**
+ * Compute the half vector between this and the other vector.
+ *
+ * @param other
+ * the other vector
+ * @return this
+ */
+ public Vector3d half(Vector3dc other) {
+ return this.set(this).add(other.x(), other.y(), other.z()).normalize();
+ }
+
+ /**
+ * Compute the half vector between this and the vector (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return this
+ */
+ public Vector3d half(double x, double y, double z) {
+ return this.set(this).add(x, y, z).normalize();
+ }
+
+ public Vector3d half(Vector3dc other, Vector3d dest) {
+ return dest.set(this).add(other.x(), other.y(), other.z()).normalize();
+ }
+
+ public Vector3d half(double x, double y, double z, Vector3d dest) {
+ return dest.set(this).add(x, y, z).normalize();
+ }
+
+ public Vector3d smoothStep(Vector3dc v, double t, Vector3d dest) {
+ double t2 = t * t;
+ double t3 = t2 * t;
+ dest.x = (x + x - v.x() - v.x()) * t3 + (3.0 * v.x() - 3.0 * x) * t2 + x * t + x;
+ dest.y = (y + y - v.y() - v.y()) * t3 + (3.0 * v.y() - 3.0 * y) * t2 + y * t + y;
+ dest.z = (z + z - v.z() - v.z()) * t3 + (3.0 * v.z() - 3.0 * z) * t2 + z * t + z;
+ return dest;
+ }
+
+ public Vector3d hermite(Vector3dc t0, Vector3dc v1, Vector3dc t1, double t, Vector3d dest) {
+ double t2 = t * t;
+ double t3 = t2 * t;
+ dest.x = (x + x - v1.x() - v1.x() + t1.x() + t0.x()) * t3 + (3.0 * v1.x() - 3.0 * x - t0.x() - t0.x() - t1.x()) * t2 + x * t + x;
+ dest.y = (y + y - v1.y() - v1.y() + t1.y() + t0.y()) * t3 + (3.0 * v1.y() - 3.0 * y - t0.y() - t0.y() - t1.y()) * t2 + y * t + y;
+ dest.z = (z + z - v1.z() - v1.z() + t1.z() + t0.z()) * t3 + (3.0 * v1.z() - 3.0 * z - t0.z() - t0.z() - t1.z()) * t2 + z * t + z;
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Vector3d lerp(Vector3dc other, double t) {
+ this.x = Math.fma(other.x() - x, t, x);
+ this.y = Math.fma(other.y() - y, t, y);
+ this.z = Math.fma(other.z() - z, t, z);
+ return this;
+ }
+
+ public Vector3d lerp(Vector3dc other, double t, Vector3d dest) {
+ dest.x = Math.fma(other.x() - x, t, x);
+ dest.y = Math.fma(other.y() - y, t, y);
+ dest.z = Math.fma(other.z() - z, t, z);
+ return dest;
+ }
+
+ public double get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Vector3i get(int mode, Vector3i dest) {
+ dest.x = Math.roundUsing(this.x(), mode);
+ dest.y = Math.roundUsing(this.y(), mode);
+ dest.z = Math.roundUsing(this.z(), mode);
+ return dest;
+ }
+
+ public Vector3f get(Vector3f dest) {
+ dest.x = (float) this.x();
+ dest.y = (float) this.y();
+ dest.z = (float) this.z();
+ return dest;
+ }
+
+ public Vector3d get(Vector3d dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ dest.z = this.z();
+ return dest;
+ }
+
+ public int maxComponent() {
+ double absX = Math.abs(x);
+ double absY = Math.abs(y);
+ double absZ = Math.abs(z);
+ if (absX >= absY && absX >= absZ) {
+ return 0;
+ } else if (absY >= absZ) {
+ return 1;
+ }
+ return 2;
+ }
+
+ public int minComponent() {
+ double absX = Math.abs(x);
+ double absY = Math.abs(y);
+ double absZ = Math.abs(z);
+ if (absX < absY && absX < absZ) {
+ return 0;
+ } else if (absY < absZ) {
+ return 1;
+ }
+ return 2;
+ }
+
+ public Vector3d orthogonalize(Vector3dc v, Vector3d dest) {
+ /*
+ * http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts
+ */
+ double rx, ry, rz;
+ if (Math.abs(v.x()) > Math.abs(v.z())) {
+ rx = -v.y();
+ ry = v.x();
+ rz = 0.0;
+ } else {
+ rx = 0.0;
+ ry = -v.z();
+ rz = v.y();
+ }
+ double invLen = Math.invsqrt(rx * rx + ry * ry + rz * rz);
+ dest.x = rx * invLen;
+ dest.y = ry * invLen;
+ dest.z = rz * invLen;
+ return dest;
+ }
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given vector v
and normalize the result.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference vector which the result should be orthogonal to
+ * @return this
+ */
+ public Vector3d orthogonalize(Vector3dc v) {
+ return orthogonalize(v, this);
+ }
+
+ public Vector3d orthogonalizeUnit(Vector3dc v, Vector3d dest) {
+ return orthogonalize(v, dest);
+ }
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given unit vector v
and normalize the result.
+ *
+ * The vector v
is assumed to be a {@link #normalize() unit} vector.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference unit vector which the result should be orthogonal to
+ * @return this
+ */
+ public Vector3d orthogonalizeUnit(Vector3dc v) {
+ return orthogonalizeUnit(v, this);
+ }
+
+ /**
+ * Set each component of this vector to the largest (closest to positive
+ * infinity) {@code double} value that is less than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector3d floor() {
+ this.x = Math.floor(x);
+ this.y = Math.floor(y);
+ this.z = Math.floor(z);
+ return this;
+ }
+
+ public Vector3d floor(Vector3d dest) {
+ dest.x = Math.floor(x);
+ dest.y = Math.floor(y);
+ dest.z = Math.floor(z);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the smallest (closest to negative
+ * infinity) {@code double} value that is greater than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector3d ceil() {
+ this.x = Math.ceil(x);
+ this.y = Math.ceil(y);
+ this.z = Math.ceil(z);
+ return this;
+ }
+
+ public Vector3d ceil(Vector3d dest) {
+ dest.x = Math.ceil(x);
+ dest.y = Math.ceil(y);
+ dest.z = Math.ceil(z);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the closest double that is equal to
+ * a mathematical integer, with ties rounding to positive infinity.
+ *
+ * @return this
+ */
+ public Vector3d round() {
+ this.x = Math.round(x);
+ this.y = Math.round(y);
+ this.z = Math.round(z);
+ return this;
+ }
+
+ public Vector3d round(Vector3d dest) {
+ dest.x = Math.round(x);
+ dest.y = Math.round(y);
+ dest.z = Math.round(z);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3dc.java
new file mode 100644
index 000000000..148505f26
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3dc.java
@@ -0,0 +1,1392 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.*;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 3-dimensional vector of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector3dc {
+
+ /**
+ * @return the value of the x component
+ */
+ double x();
+
+ /**
+ * @return the value of the y component
+ */
+ double y();
+
+ /**
+ * @return the value of the z component
+ */
+ double z();
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ * @see #get(int, DoubleBuffer)
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ * @see #get(int, DoubleBuffer)
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer getf(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ ByteBuffer getf(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector3dc getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract from this
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d sub(Vector3dc v, Vector3d dest);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract from this
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d sub(Vector3fc v, Vector3d dest);
+
+ /**
+ * Subtract (x, y, z)
from this vector and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d sub(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d add(Vector3dc v, Vector3d dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d add(Vector3fc v, Vector3d dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d add(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d fma(Vector3dc a, Vector3dc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d fma(double a, Vector3dc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d fma(Vector3dc a, Vector3fc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d fma(Vector3fc a, Vector3fc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d fma(double a, Vector3fc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulAdd(Vector3dc a, Vector3dc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulAdd(double a, Vector3dc b, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulAdd(Vector3fc a, Vector3dc b, Vector3d dest);
+
+ /**
+ * Multiply this Vector3d component-wise by another Vector3f and store the result in dest
.
+ *
+ * @param v
+ * the vector to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(Vector3fc v, Vector3d dest);
+
+ /**
+ * Multiply this by v
component-wise and store the result into dest
.
+ *
+ * @param v
+ * the vector to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(Vector3dc v, Vector3d dest);
+
+ /**
+ * Divide this Vector3d component-wise by another Vector3f and store the result in dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d div(Vector3fc v, Vector3d dest);
+
+ /**
+ * Divide this by v
component-wise and store the result into dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d div(Vector3dc v, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector3d, perform perspective division
+ * and store the result in dest
.
+ *
+ * This method uses the given w
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param w
+ * the w component to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulProject(Matrix4dc mat, double w, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector3d, perform perspective division
+ * and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulProject(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector3d, perform perspective division
+ * and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulProject(Matrix4fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(Matrix3dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(Matrix3dc mat, Vector3f dest);
+
+ /**
+ * Multiply the given matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(Matrix3fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this
by assuming a
+ * third row in the matrix of (0, 0, 1)
and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(Matrix3x2dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given matrix mat
with this
by assuming a
+ * third row in the matrix of (0, 0, 1)
and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(Matrix3x2fc mat, Vector3d dest);
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulTranspose(Matrix3dc mat, Vector3d dest);
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulTranspose(Matrix3fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulPosition(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulPosition(Matrix4fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulPosition(Matrix4x3dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulPosition(Matrix4x3fc mat, Vector3d dest);
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulTransposePosition(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulTransposePosition(Matrix4fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
, store the
+ * result in dest
and return the w component of the resulting 4D vector.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the (x, y, z)
components of the resulting vector
+ * @return the w component of the resulting 4D vector after multiplication
+ */
+ double mulPositionW(Matrix4fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
, store the
+ * result in dest
and return the w component of the resulting 4D vector.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the (x, y, z)
components of the resulting vector
+ * @return the w component of the resulting 4D vector after multiplication
+ */
+ double mulPositionW(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulDirection(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulDirection(Matrix4fc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulDirection(Matrix4x3dc mat, Vector3d dest);
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulDirection(Matrix4x3fc mat, Vector3d dest);
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulTransposeDirection(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulTransposeDirection(Matrix4fc mat, Vector3d dest);
+
+ /**
+ * Multiply this Vector3d by the given scalar value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar factor
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(double scalar, Vector3d dest);
+
+ /**
+ * Multiply the components of this Vector3f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @param z
+ * the z component to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mul(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Rotate this vector by the given quaternion quat
and store the result in dest
.
+ *
+ * @see Quaterniond#transform(Vector3d)
+ *
+ * @param quat
+ * the quaternion to rotate this vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d rotate(Quaterniondc quat, Vector3d dest);
+
+ /**
+ * Compute the quaternion representing a rotation of this
vector to point along toDir
+ * and store the result in dest
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * @see Quaterniond#rotationTo(Vector3dc, Vector3dc)
+ *
+ * @param toDir
+ * the destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotationTo(Vector3dc toDir, Quaterniond dest);
+
+ /**
+ * Compute the quaternion representing a rotation of this
vector to point along (toDirX, toDirY, toDirZ)
+ * and store the result in dest
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * @see Quaterniond#rotationTo(double, double, double, double, double, double)
+ *
+ * @param toDirX
+ * the x coordinate of the destination direction
+ * @param toDirY
+ * the y coordinate of the destination direction
+ * @param toDirZ
+ * the z coordinate of the destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaterniond rotationTo(double toDirX, double toDirY, double toDirZ, Quaterniond dest);
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param aX
+ * the x component of the rotation axis
+ * @param aY
+ * the y component of the rotation axis
+ * @param aZ
+ * the z component of the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d rotateAxis(double angle, double aX, double aY, double aZ, Vector3d dest);
+
+ /**
+ * Rotate this vector the specified radians around the X axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d rotateX(double angle, Vector3d dest);
+
+ /**
+ * Rotate this vector the specified radians around the Y axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d rotateY(double angle, Vector3d dest);
+
+ /**
+ * Rotate this vector the specified radians around the Z axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d rotateZ(double angle, Vector3d dest);
+
+ /**
+ * Divide this Vector3d by the given scalar value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d div(double scalar, Vector3d dest);
+
+ /**
+ * Divide the components of this Vector3f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @param z
+ * the z component to divide this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d div(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ double lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ double length();
+
+ /**
+ * Normalize this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d normalize(Vector3d dest);
+
+ /**
+ * Scale this vector to have the given length and store the result in dest
.
+ *
+ * @param length
+ * the desired length
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d normalize(double length, Vector3d dest);
+
+ /**
+ * Calculate the cross product of this and v2 and store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d cross(Vector3dc v, Vector3d dest);
+
+ /**
+ * Compute the cross product of this vector and (x, y, z)
and store the result in dest
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d cross(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Return the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector3dc v);
+
+ /**
+ * Return the distance between this
vector and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the euclidean distance
+ */
+ double distance(double x, double y, double z);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ double distanceSquared(Vector3dc v);
+
+ /**
+ * Return the square of the distance between this
vector and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the square of the distance
+ */
+ double distanceSquared(double x, double y, double z);
+
+ /**
+ * Return the dot product of this vector and the supplied vector.
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ double dot(Vector3dc v);
+
+ /**
+ * Return the dot product of this vector and the vector (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the dot product
+ */
+ double dot(double x, double y, double z);
+
+ /**
+ * Return the cosine of the angle between this
vector and
+ * the supplied vector. Use this instead of Math.cos(angle(v))
.
+ *
+ * @see #angle(Vector3dc)
+ *
+ * @param v
+ * the other vector
+ * @return the cosine of the angle
+ */
+ double angleCos(Vector3dc v);
+
+ /**
+ * Return the angle between this vector and the supplied vector.
+ *
+ * @see #angleCos(Vector3dc)
+ *
+ * @param v
+ * the other vector
+ * @return the angle, in radians
+ */
+ double angle(Vector3dc v);
+
+ /**
+ * Return the signed angle between this vector and the supplied vector with
+ * respect to the plane with the given normal vector n
.
+ *
+ * @see #angleCos(Vector3dc)
+ *
+ * @param v
+ * the other vector
+ * @param n
+ * the plane's normal vector
+ * @return the angle, in radians
+ */
+ double angleSigned(Vector3dc v, Vector3dc n);
+
+ /**
+ * Return the signed angle between this vector and the supplied vector with
+ * respect to the plane with the given normal vector (nx, ny, nz)
.
+ *
+ * @param x
+ * the x coordinate of the other vector
+ * @param y
+ * the y coordinate of the other vector
+ * @param z
+ * the z coordinate of the other vector
+ * @param nx
+ * the x coordinate of the plane's normal vector
+ * @param ny
+ * the y coordinate of the plane's normal vector
+ * @param nz
+ * the z coordinate of the plane's normal vector
+ * @return the angle, in radians
+ */
+ double angleSigned(double x, double y, double z, double nx, double ny, double nz);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d min(Vector3dc v, Vector3d dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d max(Vector3dc v, Vector3d dest);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d negate(Vector3d dest);
+
+ /**
+ * Compute the absolute values of the individual components of this
and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d absolute(Vector3d dest);
+
+ /**
+ * Reflect this vector about the given normal vector and store the result in dest
.
+ *
+ * @param normal
+ * the vector to reflect about
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d reflect(Vector3dc normal, Vector3d dest);
+
+ /**
+ * Reflect this vector about the given normal vector and store the result in dest
.
+ *
+ * @param x
+ * the x component of the normal
+ * @param y
+ * the y component of the normal
+ * @param z
+ * the z component of the normal
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d reflect(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Compute the half vector between this and the other vector and store the result in dest
.
+ *
+ * @param other
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d half(Vector3dc other, Vector3d dest);
+
+ /**
+ * Compute the half vector between this and the vector (x, y, z)
+ * and store the result in dest
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d half(double x, double y, double z, Vector3d dest);
+
+ /**
+ * Compute a smooth-step (i.e. hermite with zero tangents) interpolation
+ * between this
vector and the given vector v
and
+ * store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d smoothStep(Vector3dc v, double t, Vector3d dest);
+
+ /**
+ * Compute a hermite interpolation between this
vector and its
+ * associated tangent t0
and the given vector v
+ * with its tangent t1
and store the result in
+ * dest
.
+ *
+ * @param t0
+ * the tangent of this
vector
+ * @param v1
+ * the other vector
+ * @param t1
+ * the tangent of the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d hermite(Vector3dc t0, Vector3dc v1, Vector3dc t1, double t, Vector3d dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d lerp(Vector3dc other, double t, Vector3d dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..2]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..2]
+ */
+ double get(int component) throws IllegalArgumentException;
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector
+ * using the given {@link RoundingMode}.
+ *
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i get(int mode, Vector3i dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f get(Vector3f dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d get(Vector3d dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..2]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..2]
+ */
+ int minComponent();
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given vector v
, normalize the result and store it into dest
.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference vector which the result should be orthogonal to
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d orthogonalize(Vector3dc v, Vector3d dest);
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given unit vector v
, normalize the result and store it into dest
.
+ *
+ * The vector v
is assumed to be a {@link #normalize(Vector3d) unit} vector.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference unit vector which the result should be orthogonal to
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d orthogonalizeUnit(Vector3dc v, Vector3d dest);
+
+ /**
+ * Compute for each component of this vector the largest (closest to positive
+ * infinity) {@code double} value that is less than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d floor(Vector3d dest);
+
+ /**
+ * Compute for each component of this vector the smallest (closest to negative
+ * infinity) {@code double} value that is greater than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d ceil(Vector3d dest);
+
+ /**
+ * Compute for each component of this vector the closest double that is equal to
+ * a mathematical integer, with ties rounding to positive infinity and store
+ * the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d round(Vector3d dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compare the vector components of this
vector with the given vector using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param v
+ * the other vector
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the vector components are equal; false
otherwise
+ */
+ boolean equals(Vector3dc v, double delta);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y, z)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(double x, double y, double z);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3f.java
new file mode 100644
index 000000000..88c48a09e
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3f.java
@@ -0,0 +1,2086 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a Vector comprising 3 floats and associated
+ * transformations.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ * @author F. Neurath
+ */
+public class Vector3f implements Externalizable, Cloneable, Vector3fc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public float x;
+ /**
+ * The y component of the vector.
+ */
+ public float y;
+ /**
+ * The z component of the vector.
+ */
+ public float z;
+
+ /**
+ * Create a new {@link Vector3f} of (0, 0, 0)
.
+ */
+ public Vector3f() {
+ }
+
+ /**
+ * Create a new {@link Vector3f} and initialize all three components with the given value.
+ *
+ * @param d
+ * the value of all three components
+ */
+ public Vector3f(float d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ }
+
+ /**
+ * Create a new {@link Vector3f} with the given component values.
+ *
+ * @param x
+ * the value of x
+ * @param y
+ * the value of y
+ * @param z
+ * the value of z
+ */
+ public Vector3f(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3f} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector3fc} to copy the values from
+ */
+ public Vector3f(Vector3fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ }
+
+ /**
+ * Create a new {@link Vector3f} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector3ic} to copy the values from
+ */
+ public Vector3f(Vector3ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ }
+
+ /**
+ * Create a new {@link Vector3f} with the first two components from the
+ * given v
and the given z
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ * @param z
+ * the z component
+ */
+ public Vector3f(Vector2fc v, float z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3f} with the first two components from the
+ * given v
and the given z
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ * @param z
+ * the z component
+ */
+ public Vector3f(Vector2ic v, float z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3f} and initialize its three components from the first
+ * three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ */
+ public Vector3f(float[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ }
+
+ /**
+ * Create a new {@link Vector3f} and read this vector from the supplied {@link ByteBuffer}
+ * at the current buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #Vector3f(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer values will be read in x, y, z
order
+ * @see #Vector3f(int, ByteBuffer)
+ */
+ public Vector3f(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3f} and read this vector from the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index the absolute position into the ByteBuffer
+ * @param buffer values will be read in x, y, z
order
+ */
+ public Vector3f(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3f} and read this vector from the supplied {@link FloatBuffer}
+ * at the current buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is read, use {@link #Vector3f(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer values will be read in x, y, z
order
+ * @see #Vector3f(int, FloatBuffer)
+ */
+ public Vector3f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3f} and read this vector from the supplied {@link FloatBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index the absolute position into the FloatBuffer
+ * @param buffer values will be read in x, y, z
order
+ */
+ public Vector3f(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public float x() {
+ return this.x;
+ }
+
+ public float y() {
+ return this.y;
+ }
+
+ public float z() {
+ return this.z;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * @param v
+ * contains the values of x, y and z to set
+ * @return this
+ */
+ public Vector3f set(Vector3fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * Note that due to the given vector v
storing the components in double-precision,
+ * there is the possibility to lose precision.
+ *
+ * @param v
+ * contains the values of x, y and z to set
+ * @return this
+ */
+ public Vector3f set(Vector3dc v) {
+ this.x = (float) v.x();
+ this.y = (float) v.y();
+ this.z = (float) v.z();
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * @param v
+ * contains the values of x, y and z to set
+ * @return this
+ */
+ public Vector3f set(Vector3ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
+ * and the z component from the given z
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3f set(Vector2fc v, float z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
+ * and the z component from the given z
+ *
+ * @param v
+ * the {@link Vector2dc} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3f set(Vector2dc v, float z) {
+ this.x = (float) v.x();
+ this.y = (float) v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
+ * and the z component from the given z
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3f set(Vector2ic v, float z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components to the supplied value.
+ *
+ * @param d
+ * the value of all three components
+ * @return this
+ */
+ public Vector3f set(float d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3f set(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components to the supplied value.
+ *
+ * @param d
+ * the value of all three components
+ * @return this
+ */
+ public Vector3f set(double d) {
+ this.x = (float) d;
+ this.y = (float) d;
+ this.z = (float) d;
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3f set(double x, double y, double z) {
+ this.x = (float) x;
+ this.y = (float) y;
+ this.z = (float) z;
+ return this;
+ }
+
+ /**
+ * Set the three components of this vector to the first three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ * @return this
+ */
+ public Vector3f set(float[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #set(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ * @see #set(int, ByteBuffer)
+ */
+ public Vector3f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is read, use {@link #set(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ * @see #set(int, FloatBuffer)
+ */
+ public Vector3f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 3 float values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector3f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..2]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..2]
+ */
+ public Vector3f setComponent(int component, float value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector3fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one and store the result in this
.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector3f sub(Vector3fc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ this.z = z - v.z();
+ return this;
+ }
+
+ public Vector3f sub(Vector3fc v, Vector3f dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ dest.z = z - v.z();
+ return dest;
+ }
+
+ /**
+ * Decrement the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @return this
+ */
+ public Vector3f sub(float x, float y, float z) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ this.z = this.z - z;
+ return this;
+ }
+
+ public Vector3f sub(float x, float y, float z, Vector3f dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ dest.z = this.z - z;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector3f add(Vector3fc v) {
+ this.x = this.x + v.x();
+ this.y = this.y + v.y();
+ this.z = this.z + v.z();
+ return this;
+ }
+
+ public Vector3f add(Vector3fc v, Vector3f dest) {
+ dest.x = this.x + v.x();
+ dest.y = this.y + v.y();
+ dest.z = this.z + v.z();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @return this
+ */
+ public Vector3f add(float x, float y, float z) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.z = this.z + z;
+ return this;
+ }
+
+ public Vector3f add(float x, float y, float z, Vector3f dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector3f fma(Vector3fc a, Vector3fc b) {
+ this.x = Math.fma(a.x(), b.x(), x);
+ this.y = Math.fma(a.y(), b.y(), y);
+ this.z = Math.fma(a.z(), b.z(), z);
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector3f fma(float a, Vector3fc b) {
+ this.x = Math.fma(a, b.x(), x);
+ this.y = Math.fma(a, b.y(), y);
+ this.z = Math.fma(a, b.z(), z);
+ return this;
+ }
+
+ public Vector3f fma(Vector3fc a, Vector3fc b, Vector3f dest) {
+ dest.x = Math.fma(a.x(), b.x(), x);
+ dest.y = Math.fma(a.y(), b.y(), y);
+ dest.z = Math.fma(a.z(), b.z(), z);
+ return dest;
+ }
+
+ public Vector3f fma(float a, Vector3fc b, Vector3f dest) {
+ dest.x = Math.fma(a, b.x(), x);
+ dest.y = Math.fma(a, b.y(), y);
+ dest.z = Math.fma(a, b.z(), z);
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector3f mulAdd(Vector3fc a, Vector3fc b) {
+ this.x = Math.fma(x, a.x(), b.x());
+ this.y = Math.fma(y, a.y(), b.y());
+ this.z = Math.fma(z, a.z(), b.z());
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector3f mulAdd(float a, Vector3fc b) {
+ this.x = Math.fma(x, a, b.x());
+ this.y = Math.fma(y, a, b.y());
+ this.z = Math.fma(z, a, b.z());
+ return this;
+ }
+
+ public Vector3f mulAdd(Vector3fc a, Vector3fc b, Vector3f dest) {
+ dest.x = Math.fma(x, a.x(), b.x());
+ dest.y = Math.fma(y, a.y(), b.y());
+ dest.z = Math.fma(z, a.z(), b.z());
+ return dest;
+ }
+
+ public Vector3f mulAdd(float a, Vector3fc b, Vector3f dest) {
+ dest.x = Math.fma(x, a, b.x());
+ dest.y = Math.fma(y, a, b.y());
+ dest.z = Math.fma(z, a, b.z());
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector3f component-wise by another Vector3fc.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector3f mul(Vector3fc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ return this;
+ }
+
+ public Vector3f mul(Vector3fc v, Vector3f dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ return dest;
+ }
+
+ /**
+ * Divide this Vector3f component-wise by another Vector3fc.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector3f div(Vector3fc v) {
+ this.x = this.x / v.x();
+ this.y = this.y / v.y();
+ this.z = this.z / v.z();
+ return this;
+ }
+
+ public Vector3f div(Vector3fc v, Vector3f dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ dest.z = z / v.z();
+ return dest;
+ }
+
+ public Vector3f mulProject(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ float invW = 1.0f / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30()))) * invW;
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31()))) * invW;
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32()))) * invW;
+ return dest;
+ }
+
+ public Vector3f mulProject(Matrix4fc mat, float w, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ float invW = 1.0f / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector3f, perform perspective division.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulProject(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ float invW = 1.0f / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30()))) * invW;
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31()))) * invW;
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32()))) * invW;
+ return this;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector3f and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3f mul(Matrix3fc mat) {
+ float lx = x, ly = y, lz = z;
+ this.x = Math.fma(mat.m00(), lx, Math.fma(mat.m10(), ly, mat.m20() * lz));
+ this.y = Math.fma(mat.m01(), lx, Math.fma(mat.m11(), ly, mat.m21() * lz));
+ this.z = Math.fma(mat.m02(), lx, Math.fma(mat.m12(), ly, mat.m22() * lz));
+ return this;
+ }
+
+ public Vector3f mul(Matrix3fc mat, Vector3f dest) {
+ float lx = x, ly = y, lz = z;
+ dest.x = Math.fma(mat.m00(), lx, Math.fma(mat.m10(), ly, mat.m20() * lz));
+ dest.y = Math.fma(mat.m01(), lx, Math.fma(mat.m11(), ly, mat.m21() * lz));
+ dest.z = Math.fma(mat.m02(), lx, Math.fma(mat.m12(), ly, mat.m22() * lz));
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector3f and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3f mul(Matrix3dc mat) {
+ float lx = x, ly = y, lz = z;
+ this.x = (float) Math.fma(mat.m00(), lx, Math.fma(mat.m10(), ly, mat.m20() * lz));
+ this.y = (float) Math.fma(mat.m01(), lx, Math.fma(mat.m11(), ly, mat.m21() * lz));
+ this.z = (float) Math.fma(mat.m02(), lx, Math.fma(mat.m12(), ly, mat.m22() * lz));
+ return this;
+ }
+
+ public Vector3f mul(Matrix3dc mat, Vector3f dest) {
+ float lx = x, ly = y, lz = z;
+ dest.x = (float) Math.fma(mat.m00(), lx, Math.fma(mat.m10(), ly, mat.m20() * lz));
+ dest.y = (float) Math.fma(mat.m01(), lx, Math.fma(mat.m11(), ly, mat.m21() * lz));
+ dest.z = (float) Math.fma(mat.m02(), lx, Math.fma(mat.m12(), ly, mat.m22() * lz));
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix with this Vector3f and store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3f mul(Matrix3x2fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ this.z = z;
+ return this;
+ }
+
+ public Vector3f mul(Matrix3x2fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3f store the result in this
.
+ *
+ * @param mat
+ * the matrix
+ * @return this
+ */
+ public Vector3f mulTranspose(Matrix3fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ this.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ this.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ return this;
+ }
+
+ public Vector3f mulTranspose(Matrix3fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ return dest;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulPosition(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulPosition(Matrix4x3fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ return this;
+ }
+
+ public Vector3f mulPosition(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ return dest;
+ }
+
+ public Vector3f mulPosition(Matrix4x3fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulTransposePosition(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03())));
+ this.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13())));
+ this.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23())));
+ return this;
+ }
+
+ public Vector3f mulTransposePosition(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03())));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13())));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23())));
+ return dest;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and return the w component
+ * of the resulting 4D vector.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return the w component of the resulting 4D vector after multiplication
+ */
+ public float mulPositionW(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ float w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ return w;
+ }
+
+ public float mulPositionW(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ float w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33())));
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30())));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31())));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32())));
+ return w;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulDirection(Matrix4dc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = (float) Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ this.y = (float) Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ this.z = (float) Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulDirection(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ return this;
+ }
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulDirection(Matrix4x3fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ return this;
+ }
+
+ public Vector3f mulDirection(Matrix4dc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = (float) Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ dest.y = (float) Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ dest.z = (float) Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ return dest;
+ }
+
+ public Vector3f mulDirection(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ return dest;
+ }
+
+ public Vector3f mulDirection(Matrix4x3fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, mat.m20() * z));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, mat.m21() * z));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, mat.m22() * z));
+ return dest;
+ }
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @return this
+ */
+ public Vector3f mulTransposeDirection(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ this.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ this.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ return this;
+ }
+
+ public Vector3f mulTransposeDirection(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ return dest;
+ }
+
+ /**
+ * Multiply all components of this {@link Vector3f} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to multiply this vector by
+ * @return this
+ */
+ public Vector3f mul(float scalar) {
+ this.x = this.x * scalar;
+ this.y = this.y * scalar;
+ this.z = this.z * scalar;
+ return this;
+ }
+
+ public Vector3f mul(float scalar, Vector3f dest) {
+ dest.x = this.x * scalar;
+ dest.y = this.y * scalar;
+ dest.z = this.z * scalar;
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this Vector3f by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @param z
+ * the z component to multiply this vector by
+ * @return this
+ */
+ public Vector3f mul(float x, float y, float z) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ this.z = this.z * z;
+ return this;
+ }
+
+ public Vector3f mul(float x, float y, float z, Vector3f dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ dest.z = this.z * z;
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector3f} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector3f div(float scalar) {
+ float inv = 1.0f / scalar;
+ this.x = this.x * inv;
+ this.y = this.y * inv;
+ this.z = this.z * inv;
+ return this;
+ }
+
+ public Vector3f div(float scalar, Vector3f dest) {
+ float inv = 1.0f / scalar;
+ dest.x = this.x * inv;
+ dest.y = this.y * inv;
+ dest.z = this.z * inv;
+ return dest;
+ }
+
+ /**
+ * Divide the components of this Vector3f by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @param z
+ * the z component to divide this vector by
+ * @return this
+ */
+ public Vector3f div(float x, float y, float z) {
+ this.x = this.x / x;
+ this.y = this.y / y;
+ this.z = this.z / z;
+ return this;
+ }
+
+ public Vector3f div(float x, float y, float z, Vector3f dest) {
+ dest.x = this.x / x;
+ dest.y = this.y / y;
+ dest.z = this.z / z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector by the given quaternion quat
and store the result in this
.
+ *
+ * @see Quaternionfc#transform(Vector3f)
+ *
+ * @param quat
+ * the quaternion to rotate this vector
+ * @return this
+ */
+ public Vector3f rotate(Quaternionfc quat) {
+ return quat.transform(this, this);
+ }
+
+ public Vector3f rotate(Quaternionfc quat, Vector3f dest) {
+ return quat.transform(this, dest);
+ }
+
+ public Quaternionf rotationTo(Vector3fc toDir, Quaternionf dest) {
+ return dest.rotationTo(this, toDir);
+ }
+
+ public Quaternionf rotationTo(float toDirX, float toDirY, float toDirZ, Quaternionf dest) {
+ return dest.rotationTo(x, y, z, toDirX, toDirY, toDirZ);
+ }
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x component of the rotation axis
+ * @param y
+ * the y component of the rotation axis
+ * @param z
+ * the z component of the rotation axis
+ * @return this
+ */
+ public Vector3f rotateAxis(float angle, float x, float y, float z) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateX(x * angle, this);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateY(y * angle, this);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateZ(z * angle, this);
+ return rotateAxisInternal(angle, x, y, z, this);
+ }
+
+ public Vector3f rotateAxis(float angle, float aX, float aY, float aZ, Vector3f dest) {
+ if (aY == 0.0f && aZ == 0.0f && Math.absEqualsOne(aX))
+ return rotateX(aX * angle, dest);
+ else if (aX == 0.0f && aZ == 0.0f && Math.absEqualsOne(aY))
+ return rotateY(aY * angle, dest);
+ else if (aX == 0.0f && aY == 0.0f && Math.absEqualsOne(aZ))
+ return rotateZ(aZ * angle, dest);
+ return rotateAxisInternal(angle, aX, aY, aZ, dest);
+ }
+ private Vector3f rotateAxisInternal(float angle, float aX, float aY, float aZ, Vector3f dest) {
+ float hangle = angle * 0.5f;
+ float sinAngle = Math.sin(hangle);
+ float qx = aX * sinAngle, qy = aY * sinAngle, qz = aZ * sinAngle;
+ float qw = Math.cosFromSin(sinAngle, hangle);
+ float w2 = qw * qw, x2 = qx * qx, y2 = qy * qy, z2 = qz * qz, zw = qz * qw;
+ float xy = qx * qy, xz = qx * qz, yw = qy * qw, yz = qy * qz, xw = qx * qw;
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = (w2 + x2 - z2 - y2) * x + (-zw + xy - zw + xy) * y + (yw + xz + xz + yw) * z;
+ dest.y = (xy + zw + zw + xy) * x + ( y2 - z2 + w2 - x2) * y + (yz + yz - xw - xw) * z;
+ dest.z = (xz - yw + xz - yw) * x + ( yz + yz + xw + xw) * y + (z2 - y2 - x2 + w2) * z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the X axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector3f rotateX(float angle) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float y = this.y * cos - this.z * sin;
+ float z = this.y * sin + this.z * cos;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ public Vector3f rotateX(float angle, Vector3f dest) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float y = this.y * cos - this.z * sin;
+ float z = this.y * sin + this.z * cos;
+ dest.x = this.x;
+ dest.y = y;
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Y axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector3f rotateY(float angle) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos + this.z * sin;
+ float z = -this.x * sin + this.z * cos;
+ this.x = x;
+ this.z = z;
+ return this;
+ }
+
+ public Vector3f rotateY(float angle, Vector3f dest) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos + this.z * sin;
+ float z = -this.x * sin + this.z * cos;
+ dest.x = x;
+ dest.y = this.y;
+ dest.z = z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Z axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector3f rotateZ(float angle) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos - this.y * sin;
+ float y = this.x * sin + this.y * cos;
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ public Vector3f rotateZ(float angle, Vector3f dest) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos - this.y * sin;
+ float y = this.x * sin + this.y * cos;
+ dest.x = x;
+ dest.y = y;
+ dest.z = this.z;
+ return dest;
+ }
+
+ public float lengthSquared() {
+ return Math.fma(x, x, Math.fma(y, y, z * z));
+ }
+
+ /**
+ * Get the length squared of a 3-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ *
+ * @return the length squared of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static float lengthSquared(float x, float y, float z) {
+ return Math.fma(x, x, Math.fma(y, y, z * z));
+ }
+
+ public float length() {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ }
+
+ /**
+ * Get the length of a 3-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ *
+ * @return the length of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static float length(float x, float y, float z) {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ }
+
+ /**
+ * Normalize this vector.
+ *
+ * @return this
+ */
+ public Vector3f normalize() {
+ float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ this.x = this.x * scalar;
+ this.y = this.y * scalar;
+ this.z = this.z * scalar;
+ return this;
+ }
+
+ public Vector3f normalize(Vector3f dest) {
+ float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ dest.x = this.x * scalar;
+ dest.y = this.y * scalar;
+ dest.z = this.z * scalar;
+ return dest;
+ }
+
+ /**
+ * Scale this vector to have the given length.
+ *
+ * @param length
+ * the desired length
+ * @return this
+ */
+ public Vector3f normalize(float length) {
+ float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z))) * length;
+ this.x = this.x * scalar;
+ this.y = this.y * scalar;
+ this.z = this.z * scalar;
+ return this;
+ }
+
+ public Vector3f normalize(float length, Vector3f dest) {
+ float scalar = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z))) * length;
+ dest.x = this.x * scalar;
+ dest.y = this.y * scalar;
+ dest.z = this.z * scalar;
+ return dest;
+ }
+
+ /**
+ * Set this vector to be the cross product of itself and v
.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3f cross(Vector3fc v) {
+ float rx = Math.fma(y, v.z(), -z * v.y());
+ float ry = Math.fma(z, v.x(), -x * v.z());
+ float rz = Math.fma(x, v.y(), -y * v.x());
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ /**
+ * Set this vector to be the cross product of itself and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return this
+ */
+ public Vector3f cross(float x, float y, float z) {
+ float rx = Math.fma(this.y, z, -this.z * y);
+ float ry = Math.fma(this.z, x, -this.x * z);
+ float rz = Math.fma(this.x, y, -this.y * x);
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector3f cross(Vector3fc v, Vector3f dest) {
+ float rx = Math.fma(y, v.z(), -z * v.y());
+ float ry = Math.fma(z, v.x(), -x * v.z());
+ float rz = Math.fma(x, v.y(), -y * v.x());
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public Vector3f cross(float x, float y, float z, Vector3f dest) {
+ float rx = Math.fma(this.y, z, -this.z * y);
+ float ry = Math.fma(this.z, x, -this.x * z);
+ float rz = Math.fma(this.x, y, -this.y * x);
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ public float distance(Vector3fc v) {
+ float dx = this.x - v.x();
+ float dy = this.y - v.y();
+ float dz = this.z - v.z();
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)));
+ }
+
+ public float distance(float x, float y, float z) {
+ float dx = this.x - x;
+ float dy = this.y - y;
+ float dz = this.z - z;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)));
+ }
+
+ public float distanceSquared(Vector3fc v) {
+ float dx = this.x - v.x();
+ float dy = this.y - v.y();
+ float dz = this.z - v.z();
+ return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz));
+ }
+
+ public float distanceSquared(float x, float y, float z) {
+ float dx = this.x - x;
+ float dy = this.y - y;
+ float dz = this.z - z;
+ return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz));
+ }
+
+ /**
+ * Return the distance between (x1, y1, z1)
and (x2, y2, z2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @return the euclidean distance
+ */
+ public static float distance(float x1, float y1, float z1, float x2, float y2, float z2) {
+ return Math.sqrt(distanceSquared(x1, y1, z1, x2, y2, z2));
+ }
+
+ /**
+ * Return the squared distance between (x1, y1, z1)
and (x2, y2, z2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static float distanceSquared(float x1, float y1, float z1, float x2, float y2, float z2) {
+ float dx = x1 - x2;
+ float dy = y1 - y2;
+ float dz = z1 - z2;
+ return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz));
+ }
+
+ public float dot(Vector3fc v) {
+ return Math.fma(this.x, v.x(), Math.fma(this.y, v.y(), this.z * v.z()));
+ }
+
+ public float dot(float x, float y, float z) {
+ return Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ }
+
+ public float angleCos(Vector3fc v) {
+ float x = this.x, y = this.y, z = this.z;
+ float length1Squared = Math.fma(x, x, Math.fma(y, y, z * z));
+ float length2Squared = Math.fma(v.x(), v.x(), Math.fma(v.y(), v.y(), v.z() * v.z()));
+ float dot = Math.fma(x, v.x(), Math.fma(y, v.y(), z * v.z()));
+ return dot / (float)Math.sqrt(length1Squared * length2Squared);
+ }
+
+ public float angle(Vector3fc v) {
+ float cos = angleCos(v);
+ // This is because sometimes cos goes above 1 or below -1 because of lost precision
+ cos = cos < 1 ? cos : 1;
+ cos = cos > -1 ? cos : -1;
+ return Math.acos(cos);
+ }
+
+ public float angleSigned(Vector3fc v, Vector3fc n) {
+ return angleSigned(v.x(), v.y(), v.z(), n.x(), n.y(), n.z());
+ }
+
+ public float angleSigned(float x, float y, float z, float nx, float ny, float nz) {
+ float tx = this.x, ty = this.y, tz = this.z;
+ return Math.atan2(
+ (ty * z - tz * y) * nx + (tz * x - tx * z) * ny + (tx * y - ty * x) * nz,
+ tx * x + ty * y + tz * z);
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3f min(Vector3fc v) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ this.z = z < v.z() ? z : v.z();
+ return this;
+ }
+
+ public Vector3f min(Vector3fc v, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ dest.z = z < v.z() ? z : v.z();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3f max(Vector3fc v) {
+ float x = this.x, y = this.y, z = this.z;
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ this.z = z > v.z() ? z : v.z();
+ return this;
+ }
+
+ public Vector3f max(Vector3fc v, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ dest.z = z > v.z() ? z : v.z();
+ return dest;
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector3f zero() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ return this;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + " " + Runtime.format(z, formatter) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(x);
+ out.writeFloat(y);
+ out.writeFloat(z);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ set(in.readFloat(), in.readFloat(), in.readFloat());
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector3f negate() {
+ this.x = -x;
+ this.y = -y;
+ this.z = -z;
+ return this;
+ }
+
+ public Vector3f negate(Vector3f dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ return dest;
+ }
+
+ /**
+ * Set this
vector's components to their respective absolute values.
+ *
+ * @return this
+ */
+ public Vector3f absolute() {
+ this.x = Math.abs(this.x);
+ this.y = Math.abs(this.y);
+ this.z = Math.abs(this.z);
+ return this;
+ }
+
+ public Vector3f absolute(Vector3f dest) {
+ dest.x = Math.abs(this.x);
+ dest.y = Math.abs(this.y);
+ dest.z = Math.abs(this.z);
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(x);
+ result = prime * result + Float.floatToIntBits(y);
+ result = prime * result + Float.floatToIntBits(z);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Vector3f other = (Vector3f) obj;
+ if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
+ return false;
+ if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
+ return false;
+ if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Vector3fc v, float delta) {
+ if (this == v)
+ return true;
+ if (v == null)
+ return false;
+ if (!(v instanceof Vector3fc))
+ return false;
+ if (!Runtime.equals(x, v.x(), delta))
+ return false;
+ if (!Runtime.equals(y, v.y(), delta))
+ return false;
+ if (!Runtime.equals(z, v.z(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(float x, float y, float z) {
+ if (Float.floatToIntBits(this.x) != Float.floatToIntBits(x))
+ return false;
+ if (Float.floatToIntBits(this.y) != Float.floatToIntBits(y))
+ return false;
+ if (Float.floatToIntBits(this.z) != Float.floatToIntBits(z))
+ return false;
+ return true;
+ }
+
+ /**
+ * Reflect this vector about the given normal
vector.
+ *
+ * @param normal
+ * the vector to reflect about
+ * @return this
+ */
+ public Vector3f reflect(Vector3fc normal) {
+ float x = normal.x();
+ float y = normal.y();
+ float z = normal.z();
+ float dot = Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ this.x = this.x - (dot + dot) * x;
+ this.y = this.y - (dot + dot) * y;
+ this.z = this.z - (dot + dot) * z;
+ return this;
+ }
+
+ /**
+ * Reflect this vector about the given normal vector.
+ *
+ * @param x
+ * the x component of the normal
+ * @param y
+ * the y component of the normal
+ * @param z
+ * the z component of the normal
+ * @return this
+ */
+ public Vector3f reflect(float x, float y, float z) {
+ float dot = Math.fma(this.x, x, Math.fma(this.y, y, this.z * z));
+ this.x = this.x - (dot + dot) * x;
+ this.y = this.y - (dot + dot) * y;
+ this.z = this.z - (dot + dot) * z;
+ return this;
+ }
+
+ public Vector3f reflect(Vector3fc normal, Vector3f dest) {
+ return reflect(normal.x(), normal.y(), normal.z(), dest);
+ }
+
+ public Vector3f reflect(float x, float y, float z, Vector3f dest) {
+ float dot = this.dot(x, y, z);
+ dest.x = this.x - (dot + dot) * x;
+ dest.y = this.y - (dot + dot) * y;
+ dest.z = this.z - (dot + dot) * z;
+ return dest;
+ }
+
+ /**
+ * Compute the half vector between this and the other vector.
+ *
+ * @param other
+ * the other vector
+ * @return this
+ */
+ public Vector3f half(Vector3fc other) {
+ return this.set(this).add(other.x(), other.y(), other.z()).normalize();
+ }
+
+ /**
+ * Compute the half vector between this and the vector (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return this
+ */
+ public Vector3f half(float x, float y, float z) {
+ return half(x, y, z, this);
+ }
+
+ public Vector3f half(Vector3fc other, Vector3f dest) {
+ return half(other.x(), other.y(), other.z(), dest);
+ }
+
+ public Vector3f half(float x, float y, float z, Vector3f dest) {
+ return dest.set(this).add(x, y, z).normalize();
+ }
+
+ public Vector3f smoothStep(Vector3fc v, float t, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ float t2 = t * t;
+ float t3 = t2 * t;
+ dest.x = (x + x - v.x() - v.x()) * t3 + (3.0f * v.x() - 3.0f * x) * t2 + x * t + x;
+ dest.y = (y + y - v.y() - v.y()) * t3 + (3.0f * v.y() - 3.0f * y) * t2 + y * t + y;
+ dest.z = (z + z - v.z() - v.z()) * t3 + (3.0f * v.z() - 3.0f * z) * t2 + z * t + z;
+ return dest;
+ }
+
+ public Vector3f hermite(Vector3fc t0, Vector3fc v1, Vector3fc t1, float t, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z;
+ float t2 = t * t;
+ float t3 = t2 * t;
+ dest.x = (x + x - v1.x() - v1.x() + t1.x() + t0.x()) * t3 + (3.0f * v1.x() - 3.0f * x - t0.x() - t0.x() - t1.x()) * t2 + x * t + x;
+ dest.y = (y + y - v1.y() - v1.y() + t1.y() + t0.y()) * t3 + (3.0f * v1.y() - 3.0f * y - t0.y() - t0.y() - t1.y()) * t2 + y * t + y;
+ dest.z = (z + z - v1.z() - v1.z() + t1.z() + t0.z()) * t3 + (3.0f * v1.z() - 3.0f * z - t0.z() - t0.z() - t1.z()) * t2 + z * t + z;
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Vector3f lerp(Vector3fc other, float t) {
+ return lerp(other, t, this);
+ }
+
+ public Vector3f lerp(Vector3fc other, float t, Vector3f dest) {
+ dest.x = Math.fma(other.x() - x, t, x);
+ dest.y = Math.fma(other.y() - y, t, y);
+ dest.z = Math.fma(other.z() - z, t, z);
+ return dest;
+ }
+
+ public float get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Vector3i get(int mode, Vector3i dest) {
+ dest.x = Math.roundUsing(this.x(), mode);
+ dest.y = Math.roundUsing(this.y(), mode);
+ dest.z = Math.roundUsing(this.z(), mode);
+ return dest;
+ }
+
+ public Vector3f get(Vector3f dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ dest.z = this.z();
+ return dest;
+ }
+
+ public Vector3d get(Vector3d dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ dest.z = this.z();
+ return dest;
+ }
+
+ public int maxComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ float absZ = Math.abs(z);
+ if (absX >= absY && absX >= absZ) {
+ return 0;
+ } else if (absY >= absZ) {
+ return 1;
+ }
+ return 2;
+ }
+
+ public int minComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ float absZ = Math.abs(z);
+ if (absX < absY && absX < absZ) {
+ return 0;
+ } else if (absY < absZ) {
+ return 1;
+ }
+ return 2;
+ }
+
+ public Vector3f orthogonalize(Vector3fc v, Vector3f dest) {
+ /*
+ * http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts
+ */
+ float rx, ry, rz;
+ if (Math.abs(v.x()) > Math.abs(v.z())) {
+ rx = -v.y();
+ ry = v.x();
+ rz = 0.0f;
+ } else {
+ rx = 0.0f;
+ ry = -v.z();
+ rz = v.y();
+ }
+ float invLen = Math.invsqrt(rx * rx + ry * ry + rz * rz);
+ dest.x = rx * invLen;
+ dest.y = ry * invLen;
+ dest.z = rz * invLen;
+ return dest;
+ }
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given vector v
and normalize the result.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference vector which the result should be orthogonal to
+ * @return this
+ */
+ public Vector3f orthogonalize(Vector3fc v) {
+ return orthogonalize(v, this);
+ }
+
+ public Vector3f orthogonalizeUnit(Vector3fc v, Vector3f dest) {
+ return orthogonalize(v, dest);
+ }
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given unit vector v
and normalize the result.
+ *
+ * The vector v
is assumed to be a {@link #normalize() unit} vector.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference unit vector which the result should be orthogonal to
+ * @return this
+ */
+ public Vector3f orthogonalizeUnit(Vector3fc v) {
+ return orthogonalizeUnit(v, this);
+ }
+
+ /**
+ * Set each component of this vector to the largest (closest to positive
+ * infinity) {@code float} value that is less than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector3f floor() {
+ return floor(this);
+ }
+
+ public Vector3f floor(Vector3f dest) {
+ dest.x = Math.floor(x);
+ dest.y = Math.floor(y);
+ dest.z = Math.floor(z);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the smallest (closest to negative
+ * infinity) {@code float} value that is greater than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector3f ceil() {
+ return ceil(this);
+ }
+
+ public Vector3f ceil(Vector3f dest) {
+ dest.x = Math.ceil(x);
+ dest.y = Math.ceil(y);
+ dest.z = Math.ceil(z);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the closest float that is equal to
+ * a mathematical integer, with ties rounding to positive infinity.
+ *
+ * @return this
+ */
+ public Vector3f round() {
+ return round(this);
+ }
+
+ public Vector3f round(Vector3f dest) {
+ dest.x = Math.round(x);
+ dest.y = Math.round(y);
+ dest.z = Math.round(z);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z);
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3fc.java
new file mode 100644
index 000000000..2aa0dc0a0
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3fc.java
@@ -0,0 +1,1089 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 3-dimensional vector of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector3fc {
+
+ /**
+ * @return the value of the x component
+ */
+ float x();
+
+ /**
+ * @return the value of the y component
+ */
+ float y();
+
+ /**
+ * @return the value of the z component
+ */
+ float z();
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, FloatBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ * @see #get(int, FloatBuffer)
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector3fc getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f sub(Vector3fc v, Vector3f dest);
+
+ /**
+ * Decrement the components of this vector by the given values and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f sub(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f add(Vector3fc v, Vector3f dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f add(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f fma(Vector3fc a, Vector3fc b, Vector3f dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f fma(float a, Vector3fc b, Vector3f dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulAdd(Vector3fc a, Vector3fc b, Vector3f dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulAdd(float a, Vector3fc b, Vector3f dest);
+
+ /**
+ * Multiply this Vector3f component-wise by another Vector3f and store the result in dest
.
+ *
+ * @param v
+ * the vector to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(Vector3fc v, Vector3f dest);
+
+ /**
+ * Divide this Vector3f component-wise by another Vector3f and store the result in dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f div(Vector3fc v, Vector3f dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector3f, perform perspective division
+ * and store the result in dest
.
+ *
+ * This method uses w=1.0
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulProject(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector3f, perform perspective division
+ * and store the result in dest
.
+ *
+ * This method uses the given w
as the fourth vector component.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param w
+ * the w component to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulProject(Matrix4fc mat, float w, Vector3f dest);
+
+ /**
+ * Multiply the given matrix with this Vector3f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(Matrix3fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given matrix with this Vector3f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(Matrix3dc mat, Vector3f dest);
+
+ /**
+ * Multiply the given matrix mat
with this
by assuming a
+ * third row in the matrix of (0, 0, 1)
and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(Matrix3x2fc mat, Vector3f dest);
+
+ /**
+ * Multiply the transpose of the given matrix with this Vector3f and store the result in dest
.
+ *
+ * @param mat
+ * the matrix
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulTranspose(Matrix3fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulPosition(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulPosition(Matrix4x3fc mat, Vector3f dest);
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulTransposePosition(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
, store the
+ * result in dest
and return the w component of the resulting 4D vector.
+ *
+ * This method assumes the w
component of this
to be 1.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the (x, y, z)
components of the resulting vector
+ * @return the w component of the resulting 4D vector after multiplication
+ */
+ float mulPositionW(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulDirection(Matrix4dc mat, Vector3f dest);
+
+ /**
+ * Multiply the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulDirection(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply the given 4x3 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulDirection(Matrix4x3fc mat, Vector3f dest);
+
+ /**
+ * Multiply the transpose of the given 4x4 matrix mat
with this
and store the
+ * result in dest
.
+ *
+ * This method assumes the w
component of this
to be 0.0
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulTransposeDirection(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply all components of this {@link Vector3f} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(float scalar, Vector3f dest);
+
+ /**
+ * Multiply the components of this Vector3f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to multiply this vector by
+ * @param y
+ * the y component to multiply this vector by
+ * @param z
+ * the z component to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mul(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Divide all components of this {@link Vector3f} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f div(float scalar, Vector3f dest);
+
+ /**
+ * Divide the components of this Vector3f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to divide this vector by
+ * @param y
+ * the y component to divide this vector by
+ * @param z
+ * the z component to divide this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f div(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Rotate this vector by the given quaternion quat
and store the result in dest
.
+ *
+ * @see Quaternionfc#transform(Vector3f)
+ *
+ * @param quat
+ * the quaternion to rotate this vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f rotate(Quaternionfc quat, Vector3f dest);
+
+ /**
+ * Compute the quaternion representing a rotation of this
vector to point along toDir
+ * and store the result in dest
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * @see Quaternionf#rotationTo(Vector3fc, Vector3fc)
+ *
+ * @param toDir
+ * the destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotationTo(Vector3fc toDir, Quaternionf dest);
+
+ /**
+ * Compute the quaternion representing a rotation of this
vector to point along (toDirX, toDirY, toDirZ)
+ * and store the result in dest
.
+ *
+ * Because there can be multiple possible rotations, this method chooses the one with the shortest arc.
+ *
+ * @see Quaternionf#rotationTo(float, float, float, float, float, float)
+ *
+ * @param toDirX
+ * the x coordinate of the destination direction
+ * @param toDirY
+ * the y coordinate of the destination direction
+ * @param toDirZ
+ * the z coordinate of the destination direction
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Quaternionf rotationTo(float toDirX, float toDirY, float toDirZ, Quaternionf dest);
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param aX
+ * the x component of the rotation axis
+ * @param aY
+ * the y component of the rotation axis
+ * @param aZ
+ * the z component of the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f rotateAxis(float angle, float aX, float aY, float aZ, Vector3f dest);
+
+ /**
+ * Rotate this vector the specified radians around the X axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f rotateX(float angle, Vector3f dest);
+
+ /**
+ * Rotate this vector the specified radians around the Y axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f rotateY(float angle, Vector3f dest);
+
+ /**
+ * Rotate this vector the specified radians around the Z axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f rotateZ(float angle, Vector3f dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ float lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ float length();
+
+ /**
+ * Normalize this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f normalize(Vector3f dest);
+
+ /**
+ * Scale this vector to have the given length and store the result in dest
.
+ *
+ * @param length
+ * the desired length
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f normalize(float length, Vector3f dest);
+
+ /**
+ * Compute the cross product of this vector and v
and store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f cross(Vector3fc v, Vector3f dest);
+
+ /**
+ * Compute the cross product of this vector and (x, y, z)
and store the result in dest
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f cross(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Return the distance between this Vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ float distance(Vector3fc v);
+
+ /**
+ * Return the distance between this
vector and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the euclidean distance
+ */
+ float distance(float x, float y, float z);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ float distanceSquared(Vector3fc v);
+
+ /**
+ * Return the square of the distance between this
vector and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the square of the distance
+ */
+ float distanceSquared(float x, float y, float z);
+
+ /**
+ * Return the dot product of this vector and the supplied vector.
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ float dot(Vector3fc v);
+
+ /**
+ * Return the dot product of this vector and the vector (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the dot product
+ */
+ float dot(float x, float y, float z);
+
+ /**
+ * Return the cosine of the angle between this vector and the supplied vector. Use this instead of Math.cos(this.angle(v)).
+ *
+ * @see #angle(Vector3fc)
+ *
+ * @param v
+ * the other vector
+ * @return the cosine of the angle
+ */
+ float angleCos(Vector3fc v);
+
+ /**
+ * Return the angle between this vector and the supplied vector.
+ *
+ * @see #angleCos(Vector3fc)
+ *
+ * @param v
+ * the other vector
+ * @return the angle, in radians
+ */
+ float angle(Vector3fc v);
+
+ /**
+ * Return the signed angle between this vector and the supplied vector with
+ * respect to the plane with the given normal vector n
.
+ *
+ * @see #angleCos(Vector3fc)
+ *
+ * @param v
+ * the other vector
+ * @param n
+ * the plane's normal vector
+ * @return the angle, in radians
+ */
+ float angleSigned(Vector3fc v, Vector3fc n);
+
+ /**
+ * Return the signed angle between this vector and the supplied vector with
+ * respect to the plane with the given normal vector (nx, ny, nz)
.
+ *
+ * @param x
+ * the x coordinate of the other vector
+ * @param y
+ * the y coordinate of the other vector
+ * @param z
+ * the z coordinate of the other vector
+ * @param nx
+ * the x coordinate of the plane's normal vector
+ * @param ny
+ * the y coordinate of the plane's normal vector
+ * @param nz
+ * the z coordinate of the plane's normal vector
+ * @return the angle, in radians
+ */
+ float angleSigned(float x, float y, float z, float nx, float ny, float nz);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f min(Vector3fc v, Vector3f dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f max(Vector3fc v, Vector3f dest);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f negate(Vector3f dest);
+
+ /**
+ * Compute the absolute values of the individual components of this
and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f absolute(Vector3f dest);
+
+ /**
+ * Reflect this vector about the given normal
vector and store the result in dest
.
+ *
+ * @param normal
+ * the vector to reflect about
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f reflect(Vector3fc normal, Vector3f dest);
+
+ /**
+ * Reflect this vector about the given normal vector and store the result in dest
.
+ *
+ * @param x
+ * the x component of the normal
+ * @param y
+ * the y component of the normal
+ * @param z
+ * the z component of the normal
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f reflect(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Compute the half vector between this and the other vector and store the result in dest
.
+ *
+ * @param other
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f half(Vector3fc other, Vector3f dest);
+
+ /**
+ * Compute the half vector between this and the vector (x, y, z)
+ * and store the result in dest
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f half(float x, float y, float z, Vector3f dest);
+
+ /**
+ * Compute a smooth-step (i.e. hermite with zero tangents) interpolation
+ * between this
vector and the given vector v
and
+ * store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f smoothStep(Vector3fc v, float t, Vector3f dest);
+
+ /**
+ * Compute a hermite interpolation between this
vector with its
+ * associated tangent t0
and the given vector v
+ * with its tangent t1
and store the result in
+ * dest
.
+ *
+ * @param t0
+ * the tangent of this
vector
+ * @param v1
+ * the other vector
+ * @param t1
+ * the tangent of the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f hermite(Vector3fc t0, Vector3fc v1, Vector3fc t1, float t, Vector3f dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f lerp(Vector3fc other, float t, Vector3f dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..2]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..2]
+ */
+ float get(int component) throws IllegalArgumentException;
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector
+ * using the given {@link RoundingMode}.
+ *
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i get(int mode, Vector3i dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f get(Vector3f dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d get(Vector3d dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..2]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..2]
+ */
+ int minComponent();
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given vector v
, normalize the result and store it into dest
.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference vector which the result should be orthogonal to
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f orthogonalize(Vector3fc v, Vector3f dest);
+
+ /**
+ * Transform this
vector so that it is orthogonal to the given unit vector v
, normalize the result and store it into dest
.
+ *
+ * The vector v
is assumed to be a {@link #normalize(Vector3f) unit} vector.
+ *
+ * Reference: Gram–Schmidt process
+ *
+ * @param v
+ * the reference unit vector which the result should be orthogonal to
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f orthogonalizeUnit(Vector3fc v, Vector3f dest);
+
+ /**
+ * Compute for each component of this vector the largest (closest to positive
+ * infinity) {@code float} value that is less than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f floor(Vector3f dest);
+
+ /**
+ * Compute for each component of this vector the smallest (closest to negative
+ * infinity) {@code float} value that is greater than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f ceil(Vector3f dest);
+
+ /**
+ * Compute for each component of this vector the closest float that is equal to
+ * a mathematical integer, with ties rounding to positive infinity and store
+ * the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f round(Vector3f dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compare the vector components of this
vector with the given vector using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param v
+ * the other vector
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the vector components are equal; false
otherwise
+ */
+ boolean equals(Vector3fc v, float delta);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y, z)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(float x, float y, float z);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3i.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3i.java
new file mode 100644
index 000000000..ad920ae0f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3i.java
@@ -0,0 +1,1131 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a Vector comprising 3 ints and associated
+ * transformations.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ * @author Hans Uhlig
+ */
+public class Vector3i implements Externalizable, Cloneable, Vector3ic {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public int x;
+ /**
+ * The y component of the vector.
+ */
+ public int y;
+ /**
+ * The z component of the vector.
+ */
+ public int z;
+
+ /**
+ * Create a new {@link Vector3i} of (0, 0, 0)
.
+ */
+ public Vector3i() {
+ }
+
+ /**
+ * Create a new {@link Vector3i} and initialize all three components with
+ * the given value.
+ *
+ * @param d
+ * the value of all three components
+ */
+ public Vector3i(int d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the given component values.
+ *
+ * @param x
+ * the value of x
+ * @param y
+ * the value of y
+ * @param z
+ * the value of z
+ */
+ public Vector3i(int x, int y, int z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector3ic} to copy the values from
+ */
+ public Vector3i(Vector3ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the first two components from the
+ * given v
and the given z
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ * @param z
+ * the z component
+ */
+ public Vector3i(Vector2ic v, int z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the given component values and
+ * round using the given {@link RoundingMode}.
+ *
+ * @param x
+ * the value of x
+ * @param y
+ * the value of y
+ * @param z
+ * the value of z
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector3i(float x, float y, float z, int mode) {
+ this.x = Math.roundUsing(x, mode);
+ this.y = Math.roundUsing(y, mode);
+ this.z = Math.roundUsing(z, mode);
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the given component values and
+ * round using the given {@link RoundingMode}.
+ *
+ * @param x
+ * the value of x
+ * @param y
+ * the value of y
+ * @param z
+ * the value of z
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector3i(double x, double y, double z, int mode) {
+ this.x = Math.roundUsing(x, mode);
+ this.y = Math.roundUsing(y, mode);
+ this.z = Math.roundUsing(z, mode);
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the first two components from the
+ * given v
and the given z
and round using the given {@link RoundingMode}.
+ *
+ * @param v
+ * the {@link Vector2fc} to copy the values from
+ * @param z
+ * the z component
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector3i(Vector2fc v, float z, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(z, mode);
+ }
+
+ /**
+ * Create a new {@link Vector3i} and initialize its components to the rounded value of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector3fc} to round and copy the values from
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector3i(Vector3fc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(v.z(), mode);
+ }
+
+ /**
+ * Create a new {@link Vector3i} with the first two components from the
+ * given v
and the given z
and round using the given {@link RoundingMode}.
+ *
+ * @param v
+ * the {@link Vector2dc} to copy the values from
+ * @param z
+ * the z component
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector3i(Vector2dc v, float z, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(z, mode);
+ }
+
+ /**
+ * Create a new {@link Vector3i} and initialize its components to the rounded value of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector3dc} to round and copy the values from
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector3i(Vector3dc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(v.z(), mode);
+ }
+
+ /**
+ * Create a new {@link Vector3i} and initialize its three components from the first
+ * three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ */
+ public Vector3i(int[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ }
+
+ /**
+ * Create a new {@link Vector3i} and read this vector from the supplied
+ * {@link ByteBuffer} at the current buffer
+ * {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * read, use {@link #Vector3i(int, ByteBuffer)}, taking the absolute
+ * position as parameter.
+ *
+ * @see #Vector3i(int, ByteBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ */
+ public Vector3i(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3i} and read this vector from the supplied
+ * {@link ByteBuffer} starting at the specified absolute buffer
+ * position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ */
+ public Vector3i(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3i} and read this vector from the supplied
+ * {@link IntBuffer} at the current buffer
+ * {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * read, use {@link #Vector3i(int, IntBuffer)}, taking the absolute position
+ * as parameter.
+ *
+ * @see #Vector3i(int, IntBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ */
+ public Vector3i(IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector3i} and read this vector from the supplied
+ * {@link IntBuffer} starting at the specified absolute buffer
+ * position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ */
+ public Vector3i(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public int x() {
+ return this.x;
+ }
+
+ public int y() {
+ return this.y;
+ }
+
+ public int z() {
+ return this.z;
+ }
+
+ /**
+ * Set the x, y and z components to match the supplied vector.
+ *
+ * @param v
+ * contains the values of x, y and z to set
+ * @return this
+ */
+ public Vector3i set(Vector3ic v) {
+ x = v.x();
+ y = v.y();
+ z = v.z();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector3i} to the values of v using {@link RoundingMode#TRUNCATE} rounding.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector3i set(Vector3dc v) {
+ this.x = (int) v.x();
+ this.y = (int) v.y();
+ this.z = (int) v.z();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector3i} to the values of v using the given {@link RoundingMode}.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @return this
+ */
+ public Vector3i set(Vector3dc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(v.z(), mode);
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector3i} to the values of v using the given {@link RoundingMode}.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @return this
+ */
+ public Vector3i set(Vector3fc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(v.z(), mode);
+ return this;
+ }
+
+ /**
+ * Set the first two components from the given v
and the z
+ * component from the given z
+ *
+ * @param v
+ * the {@link Vector2ic} to copy the values from
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3i set(Vector2ic v, int z) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components to the supplied value.
+ *
+ * @param d
+ * the value of all three components
+ * @return this
+ */
+ public Vector3i set(int d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ return this;
+ }
+
+ /**
+ * Set the x, y and z components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector3i set(int x, int y, int z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the three components of this vector to the first three elements of the given array.
+ *
+ * @param xyz
+ * the array containing at least three elements
+ * @return this
+ */
+ public Vector3i set(int[] xyz) {
+ this.x = xyz[0];
+ this.y = xyz[1];
+ this.z = xyz[2];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * read, use {@link #set(int, ByteBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #set(int, ByteBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3i set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3i set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link IntBuffer} at the current
+ * buffer {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * read, use {@link #set(int, IntBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #set(int, IntBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3i set(IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link IntBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * values will be read in x, y, z
order
+ * @return this
+ */
+ public Vector3i set(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 3 integer values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector3i setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ public int get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..2]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..2]
+ */
+ public Vector3i setComponent(int component, int value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public IntBuffer get(IntBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public IntBuffer get(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector3ic getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one and store the result in
+ * this
.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector3i sub(Vector3ic v) {
+ this.x = this.x - v.x();
+ this.y = this.y - v.y();
+ this.z = this.z - v.z();
+ return this;
+ }
+
+ public Vector3i sub(Vector3ic v, Vector3i dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ dest.z = z - v.z();
+ return dest;
+ }
+
+ /**
+ * Decrement the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @return this
+ */
+ public Vector3i sub(int x, int y, int z) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ this.z = this.z - z;
+ return this;
+ }
+
+ public Vector3i sub(int x, int y, int z, Vector3i dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ dest.z = this.z - z;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector3i add(Vector3ic v) {
+ this.x = this.x + v.x();
+ this.y = this.y + v.y();
+ this.z = this.z + v.z();
+ return this;
+ }
+
+ public Vector3i add(Vector3ic v, Vector3i dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ dest.z = z + v.z();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @return this
+ */
+ public Vector3i add(int x, int y, int z) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.z = this.z + z;
+ return this;
+ }
+
+ public Vector3i add(int x, int y, int z, Vector3i dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ return dest;
+ }
+
+ /**
+ * Multiply all components of this {@link Vector3i} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to multiply this vector by
+ * @return this
+ */
+ public Vector3i mul(int scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ this.z = z * scalar;
+ return this;
+ }
+
+ public Vector3i mul(int scalar, Vector3i dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ dest.z = z * scalar;
+ return dest;
+ }
+
+ /**
+ * Multiply all components of this {@link Vector3i} by the given vector.
+ *
+ * @param v
+ * the vector to multiply
+ * @return this
+ */
+ public Vector3i mul(Vector3ic v) {
+ this.x = this.x * v.x();
+ this.y = this.y * v.y();
+ this.z = this.z * v.z();
+ return this;
+ }
+
+ public Vector3i mul(Vector3ic v, Vector3i dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to multiply
+ * @param y
+ * the y component to multiply
+ * @param z
+ * the z component to multiply
+ * @return this
+ */
+ public Vector3i mul(int x, int y, int z) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ this.z = this.z * z;
+ return this;
+ }
+
+ public Vector3i mul(int x, int y, int z, Vector3i dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ dest.z = this.z * z;
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector3i} by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector3i div(float scalar) {
+ float invscalar = 1.0f / scalar;
+ this.x = (int) (x * invscalar);
+ this.y = (int) (y * invscalar);
+ this.z = (int) (z * invscalar);
+ return this;
+ }
+
+ public Vector3i div(float scalar, Vector3i dest) {
+ float invscalar = 1.0f / scalar;
+ dest.x = (int) (x * invscalar);
+ dest.y = (int) (y * invscalar);
+ dest.z = (int) (z * invscalar);
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector3i} by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector3i div(int scalar) {
+ this.x = x / scalar;
+ this.y = y / scalar;
+ this.z = z / scalar;
+ return this;
+ }
+
+ public Vector3i div(int scalar, Vector3i dest) {
+ dest.x = x / scalar;
+ dest.y = y / scalar;
+ dest.z = z / scalar;
+ return dest;
+ }
+
+ public long lengthSquared() {
+ return x * x + y * y + z * z;
+ }
+
+ /**
+ * Get the length squared of a 3-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ *
+ * @return the length squared of the given vector
+ */
+ public static long lengthSquared(int x, int y, int z) {
+ return x * x + y * y + z * z;
+ }
+
+ public double length() {
+ return Math.sqrt(x * x + y * y + z * z);
+ }
+
+ /**
+ * Get the length of a 3-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ *
+ * @return the length squared of the given vector
+ */
+ public static double length(int x, int y, int z) {
+ return Math.sqrt(x * x + y * y + z * z);
+ }
+
+ public double distance(Vector3ic v) {
+ int dx = this.x - v.x();
+ int dy = this.y - v.y();
+ int dz = this.z - v.z();
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
+ }
+
+ public double distance(int x, int y, int z) {
+ int dx = this.x - x;
+ int dy = this.y - y;
+ int dz = this.z - z;
+ return Math.sqrt(dx * dx + dy * dy + dz * dz);
+ }
+
+ public long gridDistance(Vector3ic v) {
+ return Math.abs(v.x() - x()) + Math.abs(v.y() - y()) + Math.abs(v.z() - z());
+ }
+
+ public long gridDistance(int x, int y, int z) {
+ return Math.abs(x - x()) + Math.abs(y - y()) + Math.abs(z - z());
+ }
+
+ public long distanceSquared(Vector3ic v) {
+ int dx = this.x - v.x();
+ int dy = this.y - v.y();
+ int dz = this.z - v.z();
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ public long distanceSquared(int x, int y, int z) {
+ int dx = this.x - x;
+ int dy = this.y - y;
+ int dz = this.z - z;
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ /**
+ * Return the distance between (x1, y1, z1)
and (x2, y2, z2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @return the euclidean distance
+ */
+ public static double distance(int x1, int y1, int z1, int x2, int y2, int z2) {
+ return Math.sqrt(distanceSquared(x1, y1, z1, x2, y2, z2));
+ }
+
+ /**
+ * Return the squared distance between (x1, y1, z1)
and (x2, y2, z2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static long distanceSquared(int x1, int y1, int z1, int x2, int y2, int z2) {
+ int dx = x1 - x2;
+ int dy = y1 - y2;
+ int dz = z1 - z2;
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector3i zero() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ return this;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + formatter.format(x) + " " + formatter.format(y) + " " + formatter.format(z) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(x);
+ out.writeInt(y);
+ out.writeInt(z);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ x = in.readInt();
+ y = in.readInt();
+ z = in.readInt();
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector3i negate() {
+ this.x = -x;
+ this.y = -y;
+ this.z = -z;
+ return this;
+ }
+
+ public Vector3i negate(Vector3i dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3i min(Vector3ic v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ this.z = z < v.z() ? z : v.z();
+ return this;
+ }
+
+ public Vector3i min(Vector3ic v, Vector3i dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ dest.z = z < v.z() ? z : v.z();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector3i max(Vector3ic v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ this.z = z > v.z() ? z : v.z();
+ return this;
+ }
+
+ public Vector3i max(Vector3ic v, Vector3i dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ dest.z = z > v.z() ? z : v.z();
+ return dest;
+ }
+
+ public int maxComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ float absZ = Math.abs(z);
+ if (absX >= absY && absX >= absZ) {
+ return 0;
+ } else if (absY >= absZ) {
+ return 1;
+ }
+ return 2;
+ }
+
+ public int minComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ float absZ = Math.abs(z);
+ if (absX < absY && absX < absZ) {
+ return 0;
+ } else if (absY < absZ) {
+ return 1;
+ }
+ return 2;
+ }
+
+ /**
+ * Set this
vector's components to their respective absolute values.
+ *
+ * @return this
+ */
+ public Vector3i absolute() {
+ this.x = Math.abs(this.x);
+ this.y = Math.abs(this.y);
+ this.z = Math.abs(this.z);
+ return this;
+ }
+
+ public Vector3i absolute(Vector3i dest) {
+ dest.x = Math.abs(this.x);
+ dest.y = Math.abs(this.y);
+ dest.z = Math.abs(this.z);
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + x;
+ result = prime * result + y;
+ result = prime * result + z;
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Vector3i other = (Vector3i) obj;
+ if (x != other.x) {
+ return false;
+ }
+ if (y != other.y) {
+ return false;
+ }
+ if (z != other.z) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean equals(int x, int y, int z) {
+ if (this.x != x)
+ return false;
+ if (this.y != y)
+ return false;
+ if (this.z != z)
+ return false;
+ return true;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3ic.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3ic.java
new file mode 100644
index 000000000..97407e19b
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector3ic.java
@@ -0,0 +1,409 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Interface to a read-only view of a 3-dimensional vector of integers.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector3ic {
+
+ /**
+ * @return the value of the x component
+ */
+ int x();
+
+ /**
+ * @return the value of the y component
+ */
+ int y();
+
+ /**
+ * @return the value of the z component
+ */
+ int z();
+
+ /**
+ * Store this vector into the supplied {@link IntBuffer} at the current
+ * buffer {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * stored, use {@link #get(int, IntBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #get(int, IntBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ IntBuffer get(IntBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link IntBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param
+ * buffer will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ IntBuffer get(int index, IntBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * stored, use {@link #get(int, ByteBuffer)}, taking the absolute position
+ * as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector3ic getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i sub(Vector3ic v, Vector3i dest);
+
+ /**
+ * Decrement the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i sub(int x, int y, int z, Vector3i dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i add(Vector3ic v, Vector3i dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i add(int x, int y, int z, Vector3i dest);
+
+ /**
+ * Multiply the components of this vector by the given scalar and store the result in dest
.
+ *
+ * @param scalar
+ * the value to multiply this vector's components by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i mul(int scalar, Vector3i dest);
+
+ /**
+ * Multiply the supplied vector by this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to multiply
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i mul(Vector3ic v, Vector3i dest);
+
+ /**
+ * Multiply the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to multiply
+ * @param y
+ * the y component to multiply
+ * @param z
+ * the z component to multiply
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i mul(int x, int y, int z, Vector3i dest);
+
+ /**
+ * Divide all components of this {@link Vector3i} by the given scalar value
+ * and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i div(float scalar, Vector3i dest);
+
+ /**
+ * Divide all components of this {@link Vector3i} by the given scalar value
+ * and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i div(int scalar, Vector3i dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ long lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ double length();
+
+ /**
+ * Return the distance between this Vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector3ic v);
+
+ /**
+ * Return the distance between this
vector and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the euclidean distance
+ */
+ double distance(int x, int y, int z);
+
+
+ /**
+ * Return the grid distance in between (aka 1-Norm, Minkowski or Manhattan distance)
+ * (x, y)
.
+ *
+ * @param v
+ * the other vector
+ * @return the grid distance
+ */
+ long gridDistance(Vector3ic v);
+
+ /**
+ * Return the grid distance in between (aka 1-Norm, Minkowski or Manhattan distance)
+ * (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the y component of the other vector
+ * @return the grid distance
+ */
+ long gridDistance(int x, int y, int z);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ long distanceSquared(Vector3ic v);
+
+ /**
+ * Return the square of the distance between this
vector and (x, y, z)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @return the square of the distance
+ */
+ long distanceSquared(int x, int y, int z);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i negate(Vector3i dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i min(Vector3ic v, Vector3i dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i max(Vector3ic v, Vector3i dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..2]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..2]
+ */
+ int get(int component) throws IllegalArgumentException;
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..2]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..2]
+ */
+ int minComponent();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3i absolute(Vector3i dest);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y, z)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(int x, int y, int z);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4d.java
new file mode 100644
index 000000000..e19086c28
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4d.java
@@ -0,0 +1,2129 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.*;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a Vector comprising 4 doubles and associated transformations.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ * @author F. Neurath
+ */
+public class Vector4d implements Externalizable, Cloneable, Vector4dc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public double x;
+ /**
+ * The y component of the vector.
+ */
+ public double y;
+ /**
+ * The z component of the vector.
+ */
+ public double z;
+ /**
+ * The w component of the vector.
+ */
+ public double w;
+
+ /**
+ * Create a new {@link Vector4d} of (0, 0, 0, 1)
.
+ */
+ public Vector4d() {
+ this.w = 1.0;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector4dc} to copy the values from
+ */
+ public Vector4d(Vector4dc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector4ic} to copy the values from
+ */
+ public Vector4d(Vector4ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the first three components from the
+ * given v
and the given w
.
+ *
+ * @param v
+ * the {@link Vector3dc}
+ * @param w
+ * the w component
+ */
+ public Vector4d(Vector3dc v, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the first three components from the
+ * given v
and the given w
.
+ *
+ * @param v
+ * the {@link Vector3ic}
+ * @param w
+ * the w component
+ */
+ public Vector4d(Vector3ic v, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the first two components from the
+ * given v
and the given z
and w
.
+ *
+ * @param v
+ * the {@link Vector2dc}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4d(Vector2dc v, double z, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the first two components from the
+ * given v
and the given z
and w
.
+ *
+ * @param v
+ * the {@link Vector2ic}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4d(Vector2ic v, double z, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} and initialize all four components with the given value.
+ *
+ * @param d
+ * the value of all four components
+ */
+ public Vector4d(double d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ this.w = d;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector4fc} to copy the values from
+ */
+ public Vector4d(Vector4fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the x, y, and z components from the
+ * given v
and the w component from the given w
.
+ *
+ * @param v
+ * the {@link Vector3fc}
+ * @param w
+ * the w component
+ */
+ public Vector4d(Vector3fc v, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the x and y components from the
+ * given v
and the z and w components from the given z
and w
.
+ *
+ * @param v
+ * the {@link Vector2fc}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4d(Vector2fc v, double z, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} with the given component values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4d(double x, double y, double z, double w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4d} and initialize its four components from the first
+ * four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ */
+ public Vector4d(float[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ }
+
+ /**
+ * Create a new {@link Vector4d} and initialize its four components from the first
+ * four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ */
+ public Vector4d(double[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ }
+
+ /**
+ * Create a new {@link Vector4d} and read this vector from the supplied {@link ByteBuffer}
+ * at the current buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #Vector4d(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @see #Vector4d(int, ByteBuffer)
+ */
+ public Vector4d(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4d} and read this vector from the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index the absolute position into the ByteBuffer
+ * @param buffer values will be read in x, y, z, w
order
+ */
+ public Vector4d(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4d} and read this vector from the supplied {@link DoubleBuffer}
+ * at the current buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is read, use {@link #Vector4d(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer values will be read in x, y, z, w
order
+ * @see #Vector4d(int, DoubleBuffer)
+ */
+ public Vector4d(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4d} and read this vector from the supplied {@link DoubleBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index the absolute position into the DoubleBuffer
+ * @param buffer values will be read in x, y, z, w
order
+ */
+ public Vector4d(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public double x() {
+ return this.x;
+ }
+
+ public double y() {
+ return this.y;
+ }
+
+ public double z() {
+ return this.z;
+ }
+
+ public double w() {
+ return this.w;
+ }
+
+ /**
+ * Set this {@link Vector4d} to the values of the given v
.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4d set(Vector4dc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4d} to the values of the given v
.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4d set(Vector4fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4d} to the values of the given v
.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4d set(Vector4ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components of this to the components of
+ * v
and the w component to w
.
+ *
+ * @param v
+ * the {@link Vector3dc} to copy
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4d set(Vector3dc v, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components of this to the components of
+ * v
and the w component to w
.
+ *
+ * @param v
+ * the {@link Vector3ic} to copy
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4d set(Vector3ic v, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, and z components of this to the components of
+ * v
and the w component to w
.
+ *
+ * @param v
+ * the {@link Vector3fc} to copy
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4d set(Vector3fc v, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x and y components from the given v
+ * and the z and w components to the given z
and w
.
+ *
+ * @param v
+ * the {@link Vector2dc}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4d set(Vector2dc v, double z, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x and y components from the given v
+ * and the z and w components to the given z
and w
.
+ *
+ * @param v
+ * the {@link Vector2ic}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4d set(Vector2ic v, double z, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied value.
+ *
+ * @param d
+ * the value of all four components
+ * @return this
+ */
+ public Vector4d set(double d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ this.w = d;
+ return this;
+ }
+
+ /**
+ * Set the x and y components from the given v
+ * and the z and w components to the given z
and w
.
+ *
+ * @param v
+ * the {@link Vector2fc}
+ * @param z
+ * the z components
+ * @param w
+ * the w components
+ * @return this
+ */
+ public Vector4d set(Vector2fc v, double z, double w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4d set(double x, double y, double z, double w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector4d set(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the four components of this vector to the first four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ * @return this
+ */
+ public Vector4d set(double[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ return this;
+ }
+
+ /**
+ * Set the four components of this vector to the first four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ * @return this
+ */
+ public Vector4d set(float[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #set(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ * @see #set(int, ByteBuffer)
+ */
+ public Vector4d set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4d set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is read, use {@link #set(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ * @see #set(int, DoubleBuffer)
+ */
+ public Vector4d set(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4d set(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 4 double values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector4d setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..3]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..3]
+ */
+ public Vector4d setComponent(int component, double value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer get(DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public DoubleBuffer get(int index, DoubleBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getf(ByteBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer getf(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.putf(this, index, buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector4dc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector4d sub(Vector4dc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ this.z = z - v.z();
+ this.w = w - v.w();
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector4d sub(Vector4dc v, Vector4d dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ dest.z = z - v.z();
+ dest.w = w - v.w();
+ return dest;
+ }
+
+ /**
+ * Subtract the supplied vector from this one.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector4d sub(Vector4fc v) {
+ this.x = x - v.x();
+ this.y = y - v.y();
+ this.z = z - v.z();
+ this.w = w - v.w();
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ public Vector4d sub(Vector4fc v, Vector4d dest) {
+ dest.x = x - v.x();
+ dest.y = y - v.y();
+ dest.z = z - v.z();
+ dest.w = w - v.w();
+ return dest;
+ }
+
+ /**
+ * Subtract (x, y, z, w)
from this.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @return this
+ */
+ public Vector4d sub(double x, double y, double z, double w) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ this.z = this.z - z;
+ this.w = this.w - w;
+ return this;
+ }
+
+ public Vector4d sub(double x, double y, double z, double w, Vector4d dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ dest.z = this.z - z;
+ dest.w = this.w - w;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector4d add(Vector4dc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ this.z = z + v.z();
+ this.w = w + v.w();
+ return this;
+ }
+
+ public Vector4d add(Vector4dc v, Vector4d dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ dest.z = z + v.z();
+ dest.w = w + v.w();
+ return dest;
+ }
+
+ public Vector4d add(Vector4fc v, Vector4d dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ dest.z = z + v.z();
+ dest.w = w + v.w();
+ return dest;
+ }
+
+ /**
+ * Add (x, y, z, w)
to this.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param w
+ * the w component to add
+ * @return this
+ */
+ public Vector4d add(double x, double y, double z, double w) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.z = this.z + z;
+ this.w = this.w + w;
+ return this;
+ }
+
+ public Vector4d add(double x, double y, double z, double w, Vector4d dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ dest.w = this.w + w;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector4d add(Vector4fc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ this.z = z + v.z();
+ this.w = w + v.w();
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector4d fma(Vector4dc a, Vector4dc b) {
+ this.x = Math.fma(a.x(), b.x(), x);
+ this.y = Math.fma(a.y(), b.y(), y);
+ this.z = Math.fma(a.z(), b.z(), z);
+ this.w = Math.fma(a.w(), b.w(), w);
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector4d fma(double a, Vector4dc b) {
+ this.x = Math.fma(a, b.x(), x);
+ this.y = Math.fma(a, b.y(), y);
+ this.z = Math.fma(a, b.z(), z);
+ this.w = Math.fma(a, b.w(), w);
+ return this;
+ }
+
+ public Vector4d fma(Vector4dc a, Vector4dc b, Vector4d dest) {
+ dest.x = Math.fma(a.x(), b.x(), x);
+ dest.y = Math.fma(a.y(), b.y(), y);
+ dest.z = Math.fma(a.z(), b.z(), z);
+ dest.w = Math.fma(a.w(), b.w(), w);
+ return dest;
+ }
+
+ public Vector4d fma(double a, Vector4dc b, Vector4d dest) {
+ dest.x = Math.fma(a, b.x(), x);
+ dest.y = Math.fma(a, b.y(), y);
+ dest.z = Math.fma(a, b.z(), z);
+ dest.w = Math.fma(a, b.w(), w);
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector4d mulAdd(Vector4dc a, Vector4dc b) {
+ this.x = Math.fma(x, a.x(), b.x());
+ this.y = Math.fma(y, a.y(), b.y());
+ this.z = Math.fma(z, a.z(), b.z());
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector4d mulAdd(double a, Vector4dc b) {
+ this.x = Math.fma(x, a, b.x());
+ this.y = Math.fma(y, a, b.y());
+ this.z = Math.fma(z, a, b.z());
+ return this;
+ }
+
+ public Vector4d mulAdd(Vector4dc a, Vector4dc b, Vector4d dest) {
+ dest.x = Math.fma(x, a.x(), b.x());
+ dest.y = Math.fma(y, a.y(), b.y());
+ dest.z = Math.fma(z, a.z(), b.z());
+ return dest;
+ }
+
+ public Vector4d mulAdd(double a, Vector4dc b, Vector4d dest) {
+ dest.x = Math.fma(x, a, b.x());
+ dest.y = Math.fma(y, a, b.y());
+ dest.z = Math.fma(z, a, b.z());
+ return dest;
+ }
+
+ /**
+ * Multiply this {@link Vector4d} component-wise by the given {@link Vector4d}.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector4d mul(Vector4dc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ this.w = w * v.w();
+ return this;
+ }
+
+ public Vector4d mul(Vector4dc v, Vector4d dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ dest.w = w * v.w();
+ return dest;
+ }
+
+ /**
+ * Divide this {@link Vector4d} component-wise by the given {@link Vector4dc}.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector4d div(Vector4dc v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ this.z = z / v.z();
+ this.w = w / v.w();
+ return this;
+ }
+
+ public Vector4d div(Vector4dc v, Vector4d dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ dest.z = z / v.z();
+ dest.w = w / v.w();
+ return dest;
+ }
+
+ /**
+ * Multiply this {@link Vector4d} component-wise by the given {@link Vector4fc}.
+ *
+ * @param v
+ * the vector to multiply by
+ * @return this
+ */
+ public Vector4d mul(Vector4fc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ this.w = w * v.w();
+ return this;
+ }
+
+ public Vector4d mul(Vector4fc v, Vector4d dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ dest.w = w * v.w();
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this {@link Vector4d}.
+ *
+ * @param mat
+ * the matrix to multiply by
+ * @return this
+ */
+ public Vector4d mul(Matrix4dc mat) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffine(mat, this);
+ return mulGeneric(mat, this);
+ }
+
+ public Vector4d mul(Matrix4dc mat, Vector4d dest) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffine(mat, dest);
+ return mulGeneric(mat, dest);
+ }
+
+ /**
+ * Multiply the transpose of the given matrix mat
with this Vector4f and store the result in
+ * this
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply the vector with
+ * @return this
+ */
+ public Vector4d mulTranspose(Matrix4dc mat) {
+ if ((mat.properties() & Matrix4dc.PROPERTY_AFFINE) != 0)
+ return mulAffineTranspose(mat, this);
+ return mulGenericTranspose(mat, this);
+ }
+ public Vector4d mulTranspose(Matrix4dc mat, Vector4d dest) {
+ if ((mat.properties() & Matrix4dc.PROPERTY_AFFINE) != 0)
+ return mulAffineTranspose(mat, dest);
+ return mulGenericTranspose(mat, dest);
+ }
+
+ public Vector4d mulAffine(Matrix4dc mat, Vector4d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = w;
+ return dest;
+ }
+
+ private Vector4d mulGeneric(Matrix4dc mat, Vector4d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ double rw = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = rw;
+ return dest;
+ }
+
+ public Vector4d mulAffineTranspose(Matrix4dc mat, Vector4d dest) {
+ double x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ dest.w = Math.fma(mat.m30(), x, Math.fma(mat.m31(), y, mat.m32() * z + w));
+ return dest;
+ }
+ private Vector4d mulGenericTranspose(Matrix4dc mat, Vector4d dest) {
+ double x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03() * w)));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13() * w)));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23() * w)));
+ dest.w = Math.fma(mat.m30(), x, Math.fma(mat.m31(), y, Math.fma(mat.m32(), z, mat.m33() * w)));
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat with this Vector4d and store the result in
+ * this
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @return this
+ */
+ public Vector4d mul(Matrix4x3dc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector4d mul(Matrix4x3dc mat, Vector4d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = w;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat with this Vector4d and store the result in
+ * this
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @return this
+ */
+ public Vector4d mul(Matrix4x3fc mat) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ return this;
+ }
+
+ public Vector4d mul(Matrix4x3fc mat, Vector4d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = w;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this {@link Vector4d}.
+ *
+ * @param mat
+ * the matrix to multiply by
+ * @return this
+ */
+ public Vector4d mul(Matrix4fc mat) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffine(mat, this);
+ return mulGeneric(mat, this);
+ }
+
+ public Vector4d mul(Matrix4fc mat, Vector4d dest) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffine(mat, dest);
+ return mulGeneric(mat, dest);
+ }
+ private Vector4d mulAffine(Matrix4fc mat, Vector4d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = w;
+ return dest;
+ }
+ private Vector4d mulGeneric(Matrix4fc mat, Vector4d dest) {
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ double rw = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = rw;
+ return dest;
+ }
+
+ public Vector4d mulProject(Matrix4dc mat, Vector4d dest) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ dest.w = 1.0;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector4d, perform perspective division.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector4d mulProject(Matrix4dc mat) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ this.x = rx;
+ this.y = ry;
+ this.z = rz;
+ this.w = 1.0;
+ return this;
+ }
+
+ public Vector3d mulProject(Matrix4dc mat, Vector3d dest) {
+ double invW = 1.0 / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ double rx = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ double ry = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ double rz = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ dest.x = rx;
+ dest.y = ry;
+ dest.z = rz;
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector4d by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to multiply by
+ * @return this
+ */
+ public Vector4d mul(double scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ this.z = z * scalar;
+ this.w = w * scalar;
+ return this;
+ }
+
+ public Vector4d mul(double scalar, Vector4d dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ dest.z = z * scalar;
+ dest.w = w * scalar;
+ return dest;
+ }
+
+ /**
+ * Divide this Vector4d by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector4d div(double scalar) {
+ double inv = 1.0 / scalar;
+ this.x = x * inv;
+ this.y = y * inv;
+ this.z = z * inv;
+ this.w = w * inv;
+ return this;
+ }
+
+ public Vector4d div(double scalar, Vector4d dest) {
+ double inv = 1.0 / scalar;
+ dest.x = x * inv;
+ dest.y = y * inv;
+ dest.z = z * inv;
+ dest.w = w * inv;
+ return dest;
+ }
+
+ /**
+ * Transform this vector by the given quaternion quat
and store the result in this
.
+ *
+ * @see Quaterniond#transform(Vector4d)
+ *
+ * @param quat
+ * the quaternion to transform this vector
+ * @return this
+ */
+ public Vector4d rotate(Quaterniondc quat) {
+ quat.transform(this, this);
+ return this;
+ }
+
+ public Vector4d rotate(Quaterniondc quat, Vector4d dest) {
+ quat.transform(this, dest);
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x component of the rotation axis
+ * @param y
+ * the y component of the rotation axis
+ * @param z
+ * the z component of the rotation axis
+ * @return this
+ */
+ public Vector4d rotateAxis(double angle, double x, double y, double z) {
+ if (y == 0.0 && z == 0.0 && Math.absEqualsOne(x))
+ return rotateX(x * angle, this);
+ else if (x == 0.0 && z == 0.0 && Math.absEqualsOne(y))
+ return rotateY(y * angle, this);
+ else if (x == 0.0 && y == 0.0 && Math.absEqualsOne(z))
+ return rotateZ(z * angle, this);
+ return rotateAxisInternal(angle, x, y, z, this);
+ }
+
+ public Vector4d rotateAxis(double angle, double aX, double aY, double aZ, Vector4d dest) {
+ if (aY == 0.0 && aZ == 0.0 && Math.absEqualsOne(aX))
+ return rotateX(aX * angle, dest);
+ else if (aX == 0.0 && aZ == 0.0 && Math.absEqualsOne(aY))
+ return rotateY(aY * angle, dest);
+ else if (aX == 0.0 && aY == 0.0 && Math.absEqualsOne(aZ))
+ return rotateZ(aZ * angle, dest);
+ return rotateAxisInternal(angle, aX, aY, aZ, dest);
+ }
+ private Vector4d rotateAxisInternal(double angle, double aX, double aY, double aZ, Vector4d dest) {
+ double hangle = angle * 0.5;
+ double sinAngle = Math.sin(hangle);
+ double qx = aX * sinAngle, qy = aY * sinAngle, qz = aZ * sinAngle;
+ double qw = Math.cosFromSin(sinAngle, hangle);
+ double w2 = qw * qw, x2 = qx * qx, y2 = qy * qy, z2 = qz * qz, zw = qz * qw;
+ double xy = qx * qy, xz = qx * qz, yw = qy * qw, yz = qy * qz, xw = qx * qw;
+ double nx = (w2 + x2 - z2 - y2) * x + (-zw + xy - zw + xy) * y + (yw + xz + xz + yw) * z;
+ double ny = (xy + zw + zw + xy) * x + ( y2 - z2 + w2 - x2) * y + (yz + yz - xw - xw) * z;
+ double nz = (xz - yw + xz - yw) * x + ( yz + yz + xw + xw) * y + (z2 - y2 - x2 + w2) * z;
+ dest.x = nx;
+ dest.y = ny;
+ dest.z = nz;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the X axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector4d rotateX(double angle) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double y = this.y * cos - this.z * sin;
+ double z = this.y * sin + this.z * cos;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ public Vector4d rotateX(double angle, Vector4d dest) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double y = this.y * cos - this.z * sin;
+ double z = this.y * sin + this.z * cos;
+ dest.x = this.x;
+ dest.y = y;
+ dest.z = z;
+ dest.w = this.w;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Y axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector4d rotateY(double angle) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos + this.z * sin;
+ double z = -this.x * sin + this.z * cos;
+ this.x = x;
+ this.z = z;
+ return this;
+ }
+
+ public Vector4d rotateY(double angle, Vector4d dest) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos + this.z * sin;
+ double z = -this.x * sin + this.z * cos;
+ dest.x = x;
+ dest.y = this.y;
+ dest.z = z;
+ dest.w = this.w;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Z axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector4d rotateZ(double angle) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos - this.y * sin;
+ double y = this.x * sin + this.y * cos;
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ public Vector4d rotateZ(double angle, Vector4d dest) {
+ double sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ double x = this.x * cos - this.y * sin;
+ double y = this.x * sin + this.y * cos;
+ dest.x = x;
+ dest.y = y;
+ dest.z = this.z;
+ dest.w = this.w;
+ return dest;
+ }
+
+ public double lengthSquared() {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ /**
+ * Get the length squared of a 4-dimensional double-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ * @param w The vector's w component
+ *
+ * @return the length squared of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static double lengthSquared(double x, double y, double z, double w) {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ public double length() {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ }
+
+ /**
+ * Get the length of a 4-dimensional double-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ * @param w The vector's w component
+ *
+ * @return the length of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static double length(double x, double y, double z, double w) {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ }
+
+ /**
+ * Normalizes this vector.
+ *
+ * @return this
+ */
+ public Vector4d normalize() {
+ double invLength = 1.0 / length();
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ this.w = w * invLength;
+ return this;
+ }
+
+ public Vector4d normalize(Vector4d dest) {
+ double invLength = 1.0 / length();
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ dest.w = w * invLength;
+ return dest;
+ }
+
+ /**
+ * Scale this vector to have the given length.
+ *
+ * @param length
+ * the desired length
+ * @return this
+ */
+ public Vector4d normalize(double length) {
+ double invLength = 1.0 / length() * length;
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ this.w = w * invLength;
+ return this;
+ }
+
+ public Vector4d normalize(double length, Vector4d dest) {
+ double invLength = 1.0 / length() * length;
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ dest.w = w * invLength;
+ return dest;
+ }
+
+ /**
+ * Normalize this vector by computing only the norm of (x, y, z)
.
+ *
+ * @return this
+ */
+ public Vector4d normalize3() {
+ double invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ this.w = w * invLength;
+ return this;
+ }
+
+ public Vector4d normalize3(Vector4d dest) {
+ double invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ dest.w = w * invLength;
+ return dest;
+ }
+
+ public double distance(Vector4dc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ double dz = this.z - v.z();
+ double dw = this.w - v.w();
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ public double distance(double x, double y, double z, double w) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ double dz = this.z - z;
+ double dw = this.w - w;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ public double distanceSquared(Vector4dc v) {
+ double dx = this.x - v.x();
+ double dy = this.y - v.y();
+ double dz = this.z - v.z();
+ double dw = this.w - v.w();
+ return Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw)));
+ }
+
+ public double distanceSquared(double x, double y, double z, double w) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ double dz = this.z - z;
+ double dw = this.w - w;
+ return Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw)));
+ }
+
+ /**
+ * Return the distance between (x1, y1, z1, w1)
and (x2, y2, z2, w2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param w1
+ * the w component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @param w2
+ * the 2 component of the second vector
+ * @return the euclidean distance
+ */
+ public static double distance(double x1, double y1, double z1, double w1, double x2, double y2, double z2, double w2) {
+ double dx = x1 - x2;
+ double dy = y1 - y2;
+ double dz = z1 - z2;
+ double dw = w1 - w2;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ /**
+ * Return the squared distance between (x1, y1, z1, w1)
and (x2, y2, z2, w2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param w1
+ * the w component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @param w2
+ * the w component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static double distanceSquared(double x1, double y1, double z1, double w1, double x2, double y2, double z2, double w2) {
+ double dx = x1 - x2;
+ double dy = y1 - y2;
+ double dz = z1 - z2;
+ double dw = w1 - w2;
+ return Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw)));
+ }
+
+ public double dot(Vector4dc v) {
+ return Math.fma(this.x, v.x(), Math.fma(this.y, v.y(), Math.fma(this.z, v.z(), this.w * v.w())));
+ }
+
+ public double dot(double x, double y, double z, double w) {
+ return Math.fma(this.x, x, Math.fma(this.y, y, Math.fma(this.z, z, this.w * w)));
+ }
+
+ public double angleCos(Vector4dc v) {
+ double length1Squared = Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ double length2Squared = Math.fma(v.x(), v.x(), Math.fma(v.y(), v.y(), Math.fma(v.z(), v.z(), v.w() * v.w())));
+ double dot = Math.fma(x, v.x(), Math.fma(y, v.y(), Math.fma(z, v.z(), w * v.w())));
+ return dot / Math.sqrt(length1Squared * length2Squared);
+ }
+
+ public double angle(Vector4dc v) {
+ double cos = angleCos(v);
+ // This is because sometimes cos goes above 1 or below -1 because of lost precision
+ cos = cos < 1 ? cos : 1;
+ cos = cos > -1 ? cos : -1;
+ return Math.acos(cos);
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector4d zero() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 0;
+ return this;
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector4d negate() {
+ this.x = -x;
+ this.y = -y;
+ this.z = -z;
+ this.w = -w;
+ return this;
+ }
+
+ public Vector4d negate(Vector4d dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ dest.w = -w;
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4d min(Vector4dc v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ this.z = z < v.z() ? z : v.z();
+ this.w = w < v.w() ? w : v.w();
+ return this;
+ }
+
+ public Vector4d min(Vector4dc v, Vector4d dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ dest.z = z < v.z() ? z : v.z();
+ dest.w = w < v.w() ? w : v.w();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4d max(Vector4dc v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ this.z = z > v.z() ? z : v.z();
+ this.w = w > v.w() ? w : v.w();
+ return this;
+ }
+
+ public Vector4d max(Vector4dc v, Vector4d dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ dest.z = z > v.z() ? z : v.z();
+ dest.w = w > v.w() ? w : v.w();
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + " " + Runtime.format(z, formatter) + " " + Runtime.format(w, formatter) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeDouble(x);
+ out.writeDouble(y);
+ out.writeDouble(z);
+ out.writeDouble(w);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException,
+ ClassNotFoundException {
+ x = in.readDouble();
+ y = in.readDouble();
+ z = in.readDouble();
+ w = in.readDouble();
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long temp;
+ temp = Double.doubleToLongBits(w);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(x);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(y);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(z);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Vector4d other = (Vector4d) obj;
+ if (Double.doubleToLongBits(w) != Double.doubleToLongBits(other.w))
+ return false;
+ if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
+ return false;
+ if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
+ return false;
+ if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Vector4dc v, double delta) {
+ if (this == v)
+ return true;
+ if (v == null)
+ return false;
+ if (!(v instanceof Vector4dc))
+ return false;
+ if (!Runtime.equals(x, v.x(), delta))
+ return false;
+ if (!Runtime.equals(y, v.y(), delta))
+ return false;
+ if (!Runtime.equals(z, v.z(), delta))
+ return false;
+ if (!Runtime.equals(w, v.w(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(double x, double y, double z, double w) {
+ if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(x))
+ return false;
+ if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(y))
+ return false;
+ if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(z))
+ return false;
+ if (Double.doubleToLongBits(this.w) != Double.doubleToLongBits(w))
+ return false;
+ return true;
+ }
+
+ public Vector4d smoothStep(Vector4dc v, double t, Vector4d dest) {
+ double t2 = t * t;
+ double t3 = t2 * t;
+ dest.x = (x + x - v.x() - v.x()) * t3 + (3.0 * v.x() - 3.0 * x) * t2 + x * t + x;
+ dest.y = (y + y - v.y() - v.y()) * t3 + (3.0 * v.y() - 3.0 * y) * t2 + y * t + y;
+ dest.z = (z + z - v.z() - v.z()) * t3 + (3.0 * v.z() - 3.0 * z) * t2 + z * t + z;
+ dest.w = (w + w - v.w() - v.w()) * t3 + (3.0 * v.w() - 3.0 * w) * t2 + w * t + w;
+ return dest;
+ }
+
+ public Vector4d hermite(Vector4dc t0, Vector4dc v1, Vector4dc t1, double t, Vector4d dest) {
+ double t2 = t * t;
+ double t3 = t2 * t;
+ dest.x = (x + x - v1.x() - v1.x() + t1.x() + t0.x()) * t3 + (3.0 * v1.x() - 3.0 * x - t0.x() - t0.x() - t1.x()) * t2 + x * t + x;
+ dest.y = (y + y - v1.y() - v1.y() + t1.y() + t0.y()) * t3 + (3.0 * v1.y() - 3.0 * y - t0.y() - t0.y() - t1.y()) * t2 + y * t + y;
+ dest.z = (z + z - v1.z() - v1.z() + t1.z() + t0.z()) * t3 + (3.0 * v1.z() - 3.0 * z - t0.z() - t0.z() - t1.z()) * t2 + z * t + z;
+ dest.w = (w + w - v1.w() - v1.w() + t1.w() + t0.w()) * t3 + (3.0 * v1.w() - 3.0 * w - t0.w() - t0.w() - t1.w()) * t2 + w * t + w;
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Vector4d lerp(Vector4dc other, double t) {
+ this.x = Math.fma(other.x() - x, t, x);
+ this.y = Math.fma(other.y() - y, t, y);
+ this.z = Math.fma(other.z() - z, t, z);
+ this.w = Math.fma(other.w() - w, t, w);
+ return this;
+ }
+
+ public Vector4d lerp(Vector4dc other, double t, Vector4d dest) {
+ dest.x = Math.fma(other.x() - x, t, x);
+ dest.y = Math.fma(other.y() - y, t, y);
+ dest.z = Math.fma(other.z() - z, t, z);
+ dest.w = Math.fma(other.w() - w, t, w);
+ return dest;
+ }
+
+ public double get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Vector4i get(int mode, Vector4i dest) {
+ dest.x = Math.roundUsing(this.x(), mode);
+ dest.y = Math.roundUsing(this.y(), mode);
+ dest.z = Math.roundUsing(this.z(), mode);
+ dest.w = Math.roundUsing(this.w(), mode);
+ return dest;
+ }
+
+ public Vector4f get(Vector4f dest) {
+ dest.x = (float) this.x();
+ dest.y = (float) this.y();
+ dest.z = (float) this.z();
+ dest.w = (float) this.w();
+ return dest;
+ }
+
+ public Vector4d get(Vector4d dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ dest.z = this.z();
+ dest.w = this.w();
+ return dest;
+ }
+
+ public int maxComponent() {
+ double absX = Math.abs(x);
+ double absY = Math.abs(y);
+ double absZ = Math.abs(z);
+ double absW = Math.abs(w);
+ if (absX >= absY && absX >= absZ && absX >= absW) {
+ return 0;
+ } else if (absY >= absZ && absY >= absW) {
+ return 1;
+ } else if (absZ >= absW) {
+ return 2;
+ }
+ return 3;
+ }
+
+ public int minComponent() {
+ double absX = Math.abs(x);
+ double absY = Math.abs(y);
+ double absZ = Math.abs(z);
+ double absW = Math.abs(w);
+ if (absX < absY && absX < absZ && absX < absW) {
+ return 0;
+ } else if (absY < absZ && absY < absW) {
+ return 1;
+ } else if (absZ < absW) {
+ return 2;
+ }
+ return 3;
+ }
+
+ /**
+ * Set each component of this vector to the largest (closest to positive
+ * infinity) {@code double} value that is less than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector4d floor() {
+ this.x = Math.floor(x);
+ this.y = Math.floor(y);
+ this.z = Math.floor(z);
+ this.w = Math.floor(w);
+ return this;
+ }
+
+ public Vector4d floor(Vector4d dest) {
+ dest.x = Math.floor(x);
+ dest.y = Math.floor(y);
+ dest.z = Math.floor(z);
+ dest.w = Math.floor(w);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the smallest (closest to negative
+ * infinity) {@code double} value that is greater than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector4d ceil() {
+ this.x = Math.ceil(x);
+ this.y = Math.ceil(y);
+ this.z = Math.ceil(z);
+ this.w = Math.ceil(w);
+ return this;
+ }
+
+ public Vector4d ceil(Vector4d dest) {
+ dest.x = Math.ceil(x);
+ dest.y = Math.ceil(y);
+ dest.z = Math.ceil(z);
+ dest.w = Math.ceil(w);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the closest double that is equal to
+ * a mathematical integer, with ties rounding to positive infinity.
+ *
+ * @return this
+ */
+ public Vector4d round() {
+ this.x = Math.round(x);
+ this.y = Math.round(y);
+ this.z = Math.round(z);
+ this.w = Math.round(w);
+ return this;
+ }
+
+ public Vector4d round(Vector4d dest) {
+ dest.x = Math.round(x);
+ dest.y = Math.round(y);
+ dest.z = Math.round(z);
+ dest.w = Math.round(w);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z) && Math.isFinite(w);
+ }
+
+ /**
+ * Compute the absolute of each of this vector's components.
+ *
+ * @return this
+ */
+ public Vector4d absolute() {
+ this.x = Math.abs(x);
+ this.y = Math.abs(y);
+ this.z = Math.abs(z);
+ this.w = Math.abs(w);
+ return this;
+ }
+
+ public Vector4d absolute(Vector4d dest) {
+ dest.x = Math.abs(x);
+ dest.y = Math.abs(y);
+ dest.z = Math.abs(z);
+ dest.w = Math.abs(w);
+ return dest;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4dc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4dc.java
new file mode 100644
index 000000000..d485096d9
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4dc.java
@@ -0,0 +1,933 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 4-dimensional vector of double-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector4dc {
+
+ /**
+ * @return the value of the x component
+ */
+ double x();
+
+ /**
+ * @return the value of the y component
+ */
+ double y();
+
+ /**
+ * @return the value of the z component
+ */
+ double z();
+
+ /**
+ * @return the value of the w component
+ */
+ double w();
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link DoubleBuffer} at the current
+ * buffer {@link DoubleBuffer#position() position}.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * In order to specify the offset into the DoubleBuffer at which
+ * the vector is stored, use {@link #get(int, DoubleBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ * @see #get(int, DoubleBuffer)
+ */
+ DoubleBuffer get(DoubleBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link DoubleBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given DoubleBuffer.
+ *
+ * @param index
+ * the absolute position into the DoubleBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ DoubleBuffer get(int index, DoubleBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ * @see #get(int, DoubleBuffer)
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer getf(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * Please note that due to this vector storing double values those values will potentially
+ * lose precision when they are converted to float values before being put into the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ ByteBuffer getf(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector4dc getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d sub(Vector4dc v, Vector4d dest);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d sub(Vector4fc v, Vector4d dest);
+
+ /**
+ * Subtract (x, y, z, w)
from this and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d sub(double x, double y, double z, double w, Vector4d dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d add(Vector4dc v, Vector4d dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d add(Vector4fc v, Vector4d dest);
+
+ /**
+ * Add (x, y, z, w)
to this and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d add(double x, double y, double z, double w, Vector4d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d fma(Vector4dc a, Vector4dc b, Vector4d dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d fma(double a, Vector4dc b, Vector4d dest);
+
+ /**
+ * Multiply this {@link Vector4d} component-wise by the given {@link Vector4dc} and store the result in dest
.
+ *
+ * @param v
+ * the vector to multiply this by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mul(Vector4dc v, Vector4d dest);
+
+ /**
+ * Multiply this {@link Vector4d} component-wise by the given {@link Vector4fc} and store the result in dest
.
+ *
+ * @param v
+ * the vector to multiply this by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mul(Vector4fc v, Vector4d dest);
+
+ /**
+ * Divide this {@link Vector4d} component-wise by the given {@link Vector4dc} and store the result in dest
.
+ *
+ * @param v
+ * the vector to divide this by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d div(Vector4dc v, Vector4d dest);
+
+ /**
+ * Multiply the given matrix mat with this {@link Vector4d} and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mul(Matrix4dc mat, Vector4d dest);
+
+ /**
+ * Multiply the given matrix mat with this Vector4d and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4d mul(Matrix4x3dc mat, Vector4d dest);
+
+ /**
+ * Multiply the given matrix mat with this Vector4d and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4d mul(Matrix4x3fc mat, Vector4d dest);
+
+ /**
+ * Multiply the given matrix mat with this Vector4d and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this
by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mul(Matrix4fc mat, Vector4d dest);
+
+ /**
+ * Multiply the transpose of the given matrix mat
with this Vector4d and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4d mulTranspose(Matrix4dc mat, Vector4d dest);
+
+ /**
+ * Multiply the given affine matrix mat with this Vector4d and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the affine matrix to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4d mulAffine(Matrix4dc mat, Vector4d dest);
+
+ /**
+ * Multiply the transpose of the given affine matrix mat
with this Vector4d and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the affine matrix whose transpose to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4d mulAffineTranspose(Matrix4dc mat, Vector4d dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector4d, perform perspective division
+ * and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mulProject(Matrix4dc mat, Vector4d dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector4d, perform perspective division
+ * and store the (x, y, z)
result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3d mulProject(Matrix4dc mat, Vector3d dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mulAdd(Vector4dc a, Vector4dc b, Vector4d dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mulAdd(double a, Vector4dc b, Vector4d dest);
+
+ /**
+ * Multiply this Vector4d by the given scalar value and store the result in dest
.
+ *
+ * @param scalar
+ * the factor to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d mul(double scalar, Vector4d dest);
+
+ /**
+ * Divide this Vector4d by the given scalar value and store the result in dest
.
+ *
+ * @param scalar
+ * the factor to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d div(double scalar, Vector4d dest);
+
+ /**
+ * Transform this vector by the given quaternion quat
and store the result in dest
.
+ *
+ * @see Quaterniond#transform(Vector4d)
+ *
+ * @param quat
+ * the quaternion to transform this vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d rotate(Quaterniondc quat, Vector4d dest);
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param aX
+ * the x component of the rotation axis
+ * @param aY
+ * the y component of the rotation axis
+ * @param aZ
+ * the z component of the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d rotateAxis(double angle, double aX, double aY, double aZ, Vector4d dest);
+
+ /**
+ * Rotate this vector the specified radians around the X axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d rotateX(double angle, Vector4d dest);
+
+ /**
+ * Rotate this vector the specified radians around the Y axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d rotateY(double angle, Vector4d dest);
+
+ /**
+ * Rotate this vector the specified radians around the Z axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d rotateZ(double angle, Vector4d dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ double lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ double length();
+
+ /**
+ * Normalizes this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d normalize(Vector4d dest);
+
+ /**
+ * Scale this vector to have the given length and store the result in dest
.
+ *
+ * @param length
+ * the desired length
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d normalize(double length, Vector4d dest);
+
+ /**
+ * Normalize this vector by computing only the norm of (x, y, z)
and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d normalize3(Vector4d dest);
+
+ /**
+ * Return the distance between this Vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector4dc v);
+
+ /**
+ * Return the distance between this
vector and (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the euclidean distance
+ */
+ double distance(double x, double y, double z, double w);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ double distanceSquared(Vector4dc v);
+
+ /**
+ * Return the square of the distance between this
vector and
+ * (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the square of the distance
+ */
+ double distanceSquared(double x, double y, double z, double w);
+
+ /**
+ * Compute the dot product (inner product) of this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ double dot(Vector4dc v);
+
+ /**
+ * Compute the dot product (inner product) of this vector and (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the dot product
+ */
+ double dot(double x, double y, double z, double w);
+
+ /**
+ * Return the cosine of the angle between this vector and the supplied vector.
+ *
+ * Use this instead of Math.cos(angle(v))
.
+ *
+ * @see #angle(Vector4dc)
+ *
+ * @param v
+ * the other vector
+ * @return the cosine of the angle
+ */
+ double angleCos(Vector4dc v);
+
+ /**
+ * Return the angle between this vector and the supplied vector.
+ *
+ * @see #angleCos(Vector4dc)
+ *
+ * @param v
+ * the other vector
+ * @return the angle, in radians
+ */
+ double angle(Vector4dc v);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d negate(Vector4d dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d min(Vector4dc v, Vector4d dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d max(Vector4dc v, Vector4d dest);
+
+ /**
+ * Compute a smooth-step (i.e. hermite with zero tangents) interpolation
+ * between this
vector and the given vector v
and
+ * store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d smoothStep(Vector4dc v, double t, Vector4d dest);
+
+ /**
+ * Compute a hermite interpolation between this
vector and its
+ * associated tangent t0
and the given vector v
+ * with its tangent t1
and store the result in
+ * dest
.
+ *
+ * @param t0
+ * the tangent of this
vector
+ * @param v1
+ * the other vector
+ * @param t1
+ * the tangent of the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d hermite(Vector4dc t0, Vector4dc v1, Vector4dc t1, double t, Vector4d dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d lerp(Vector4dc other, double t, Vector4d dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..3]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..3]
+ */
+ double get(int component) throws IllegalArgumentException;
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector
+ * using the given {@link RoundingMode}.
+ *
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i get(int mode, Vector4i dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f get(Vector4f dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d get(Vector4d dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..3]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..3]
+ */
+ int minComponent();
+
+ /**
+ * Compute for each component of this vector the largest (closest to positive
+ * infinity) {@code double} value that is less than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d floor(Vector4d dest);
+
+ /**
+ * Compute for each component of this vector the smallest (closest to negative
+ * infinity) {@code double} value that is greater than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d ceil(Vector4d dest);
+
+ /**
+ * Compute for each component of this vector the closest double that is equal to
+ * a mathematical integer, with ties rounding to positive infinity and store
+ * the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d round(Vector4d dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Double#isNaN() NaN} and not
+ * {@link Double#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d absolute(Vector4d dest);
+
+ /**
+ * Compare the vector components of this
vector with the given vector using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param v
+ * the other vector
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the vector components are equal; false
otherwise
+ */
+ boolean equals(Vector4dc v, double delta);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y, z, w)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @param w
+ * the w component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(double x, double y, double z, double w);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4f.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4f.java
new file mode 100644
index 000000000..185ab4ca3
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4f.java
@@ -0,0 +1,1939 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a Vector comprising 4 floats and associated
+ * transformations.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ * @author F. Neurath
+ */
+public class Vector4f implements Externalizable, Cloneable, Vector4fc {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public float x;
+ /**
+ * The y component of the vector.
+ */
+ public float y;
+ /**
+ * The z component of the vector.
+ */
+ public float z;
+ /**
+ * The w component of the vector.
+ */
+ public float w;
+
+ /**
+ * Create a new {@link Vector4f} of (0, 0, 0, 1)
.
+ */
+ public Vector4f() {
+ this.w = 1.0f;
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector4fc} to copy the values from
+ */
+ public Vector4f(Vector4fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector4ic} to copy the values from
+ */
+ public Vector4f(Vector4ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the first three components from the
+ * given v
and the given w
.
+ *
+ * @param v
+ * the {@link Vector3fc}
+ * @param w
+ * the w component
+ */
+ public Vector4f(Vector3fc v, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the first three components from the
+ * given v
and the given w
.
+ *
+ * @param v
+ * the {@link Vector3ic}
+ * @param w
+ * the w component
+ */
+ public Vector4f(Vector3ic v, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the first two components from the
+ * given v
and the given z
, and w
.
+ *
+ * @param v
+ * the {@link Vector2fc}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4f(Vector2fc v, float z, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the first two components from the
+ * given v
and the given z
, and w
.
+ *
+ * @param v
+ * the {@link Vector2ic}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4f(Vector2ic v, float z, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4f} and initialize all four components with the given value.
+ *
+ * @param d
+ * the value of all four components
+ */
+ public Vector4f(float d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ this.w = d;
+ }
+
+ /**
+ * Create a new {@link Vector4f} with the given component values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4f(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4f} and initialize its four components from the first
+ * four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ */
+ public Vector4f(float[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ }
+
+ /**
+ * Create a new {@link Vector4f} and read this vector from the supplied {@link ByteBuffer}
+ * at the current buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #Vector4f(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @see #Vector4f(int, ByteBuffer)
+ */
+ public Vector4f(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4f} and read this vector from the supplied {@link ByteBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ */
+ public Vector4f(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4f} and read this vector from the supplied {@link FloatBuffer}
+ * at the current buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is read, use {@link #Vector4f(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @see #Vector4f(int, FloatBuffer)
+ */
+ public Vector4f(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4f} and read this vector from the supplied {@link FloatBuffer}
+ * starting at the specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ */
+ public Vector4f(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public float x() {
+ return this.x;
+ }
+
+ public float y() {
+ return this.y;
+ }
+
+ public float z() {
+ return this.z;
+ }
+
+ public float w() {
+ return this.w;
+ }
+
+ /**
+ * Set this {@link Vector4f} to the values of the given v
.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4f set(Vector4fc v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4f} to the values of the given v
.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4f set(Vector4ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4f} to the values of the given v
.
+ *
+ * Note that due to the given vector v
storing the components in double-precision,
+ * there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4f set(Vector4dc v) {
+ this.x = (float) v.x();
+ this.y = (float) v.y();
+ this.z = (float) v.z();
+ this.w = (float) v.w();
+ return this;
+ }
+
+ /**
+ * Set the first three components of this to the components of
+ * v
and the last component to w
.
+ *
+ * @param v
+ * the {@link Vector3fc} to copy
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4f set(Vector3fc v, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the first three components of this to the components of
+ * v
and the last component to w
.
+ *
+ * @param v
+ * the {@link Vector3ic} to copy
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4f set(Vector3ic v, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Sets the first two components of this to the components of given v
+ * and last two components to the given z
, and w
.
+ *
+ * @param v
+ * the {@link Vector2fc}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4f set(Vector2fc v, float z, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Sets the first two components of this to the components of given v
+ * and last two components to the given z
, and w
.
+ *
+ * @param v
+ * the {@link Vector2ic}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4f set(Vector2ic v, float z, float w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied value.
+ *
+ * @param d
+ * the value of all four components
+ * @return this
+ */
+ public Vector4f set(float d) {
+ this.x = d;
+ this.y = d;
+ this.z = d;
+ this.w = d;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4f set(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @return this
+ */
+ public Vector4f set(float x, float y, float z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied value.
+ *
+ * @param d
+ * the value of all four components
+ * @return this
+ */
+ public Vector4f set(double d) {
+ this.x = (float) d;
+ this.y = (float) d;
+ this.z = (float) d;
+ this.w = (float) d;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4f set(double x, double y, double z, double w) {
+ this.x = (float) x;
+ this.y = (float) y;
+ this.z = (float) z;
+ this.w = (float) w;
+ return this;
+ }
+
+ /**
+ * Set the four components of this vector to the first four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ * @return this
+ */
+ public Vector4f set(float[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is read, use {@link #set(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ * @see #set(int, ByteBuffer)
+ */
+ public Vector4f set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4f set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is read, use {@link #set(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ * @see #set(int, FloatBuffer)
+ */
+ public Vector4f set(FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4f set(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 4 float values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector4f setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..3]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..3]
+ */
+ public Vector4f setComponent(int component, float value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public FloatBuffer get(FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public FloatBuffer get(int index, FloatBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector4fc getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector4f sub(Vector4fc v) {
+ this.x = this.x - v.x();
+ this.y = this.y - v.y();
+ this.z = this.z - v.z();
+ this.w = this.w - v.w();
+ return this;
+ }
+
+ /**
+ * Subtract (x, y, z, w)
from this.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @return this
+ */
+ public Vector4f sub(float x, float y, float z, float w) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ this.z = this.z - z;
+ this.w = this.w - w;
+ return this;
+ }
+
+ public Vector4f sub(Vector4fc v, Vector4f dest) {
+ dest.x = this.x - v.x();
+ dest.y = this.y - v.y();
+ dest.z = this.z - v.z();
+ dest.w = this.w - v.w();
+ return dest;
+ }
+
+ public Vector4f sub(float x, float y, float z, float w, Vector4f dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ dest.z = this.z - z;
+ dest.w = this.w - w;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector4f add(Vector4fc v) {
+ this.x = x + v.x();
+ this.y = y + v.y();
+ this.z = z + v.z();
+ this.w = w + v.w();
+ return this;
+ }
+
+ public Vector4f add(Vector4fc v, Vector4f dest) {
+ dest.x = x + v.x();
+ dest.y = y + v.y();
+ dest.z = z + v.z();
+ dest.w = w + v.w();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param w
+ * the w component to add
+ * @return this
+ */
+ public Vector4f add(float x, float y, float z, float w) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.z = this.z + z;
+ this.w = this.w + w;
+ return this;
+ }
+
+ public Vector4f add(float x, float y, float z, float w, Vector4f dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ dest.w = this.w + w;
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector4f fma(Vector4fc a, Vector4fc b) {
+ this.x = Math.fma(a.x(), b.x(), x);
+ this.y = Math.fma(a.y(), b.y(), y);
+ this.z = Math.fma(a.z(), b.z(), z);
+ this.w = Math.fma(a.w(), b.w(), w);
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @return this
+ */
+ public Vector4f fma(float a, Vector4fc b) {
+ this.x = Math.fma(a, b.x(), x);
+ this.y = Math.fma(a, b.y(), y);
+ this.z = Math.fma(a, b.z(), z);
+ this.w = Math.fma(a, b.w(), w);
+ return this;
+ }
+
+ public Vector4f fma(Vector4fc a, Vector4fc b, Vector4f dest) {
+ dest.x = Math.fma(a.x(), b.x(), x);
+ dest.y = Math.fma(a.y(), b.y(), y);
+ dest.z = Math.fma(a.z(), b.z(), z);
+ dest.w = Math.fma(a.w(), b.w(), w);
+ return dest;
+ }
+
+ public Vector4f fma(float a, Vector4fc b, Vector4f dest) {
+ dest.x = Math.fma(a, b.x(), x);
+ dest.y = Math.fma(a, b.y(), y);
+ dest.z = Math.fma(a, b.z(), z);
+ dest.w = Math.fma(a, b.w(), w);
+ return dest;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector4f mulAdd(Vector4fc a, Vector4fc b) {
+ this.x = Math.fma(x, a.x(), b.x());
+ this.y = Math.fma(y, a.y(), b.y());
+ this.z = Math.fma(z, a.z(), b.z());
+ return this;
+ }
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in this
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @return this
+ */
+ public Vector4f mulAdd(float a, Vector4fc b) {
+ this.x = Math.fma(x, a, b.x());
+ this.y = Math.fma(y, a, b.y());
+ this.z = Math.fma(z, a, b.z());
+ return this;
+ }
+
+ public Vector4f mulAdd(Vector4fc a, Vector4fc b, Vector4f dest) {
+ dest.x = Math.fma(x, a.x(), b.x());
+ dest.y = Math.fma(y, a.y(), b.y());
+ dest.z = Math.fma(z, a.z(), b.z());
+ return dest;
+ }
+
+ public Vector4f mulAdd(float a, Vector4fc b, Vector4f dest) {
+ dest.x = Math.fma(x, a, b.x());
+ dest.y = Math.fma(y, a, b.y());
+ dest.z = Math.fma(z, a, b.z());
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector4f component-wise by another Vector4f.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4f mul(Vector4fc v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ this.w = w * v.w();
+ return this;
+ }
+
+ public Vector4f mul(Vector4fc v, Vector4f dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ dest.w = w * v.w();
+ return dest;
+ }
+
+ /**
+ * Divide this Vector4f component-wise by another Vector4f.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector4f div(Vector4fc v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ this.z = z / v.z();
+ this.w = w / v.w();
+ return this;
+ }
+
+ public Vector4f div(Vector4fc v, Vector4f dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ dest.z = z / v.z();
+ dest.w = w / v.w();
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat with this Vector4f and store the result in
+ * this
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @return this
+ */
+ public Vector4f mul(Matrix4fc mat) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffine(mat, this);
+ return mulGeneric(mat, this);
+ }
+ public Vector4f mul(Matrix4fc mat, Vector4f dest) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffine(mat, dest);
+ return mulGeneric(mat, dest);
+ }
+
+ /**
+ * Multiply the transpose of the given matrix mat
with this Vector4f and store the result in
+ * this
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply the vector with
+ * @return this
+ */
+ public Vector4f mulTranspose(Matrix4fc mat) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffineTranspose(mat, this);
+ return mulGenericTranspose(mat, this);
+ }
+ public Vector4f mulTranspose(Matrix4fc mat, Vector4f dest) {
+ if ((mat.properties() & Matrix4fc.PROPERTY_AFFINE) != 0)
+ return mulAffineTranspose(mat, dest);
+ return mulGenericTranspose(mat, dest);
+ }
+
+ public Vector4f mulAffine(Matrix4fc mat, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.w = w;
+ return dest;
+ }
+
+ private Vector4f mulGeneric(Matrix4fc mat, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.w = Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ return dest;
+ }
+
+ public Vector4f mulAffineTranspose(Matrix4fc mat, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, mat.m02() * z));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, mat.m12() * z));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, mat.m22() * z));
+ dest.w = Math.fma(mat.m30(), x, Math.fma(mat.m31(), y, mat.m32() * z + w));
+ return dest;
+ }
+ private Vector4f mulGenericTranspose(Matrix4fc mat, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m01(), y, Math.fma(mat.m02(), z, mat.m03() * w)));
+ dest.y = Math.fma(mat.m10(), x, Math.fma(mat.m11(), y, Math.fma(mat.m12(), z, mat.m13() * w)));
+ dest.z = Math.fma(mat.m20(), x, Math.fma(mat.m21(), y, Math.fma(mat.m22(), z, mat.m23() * w)));
+ dest.w = Math.fma(mat.m30(), x, Math.fma(mat.m31(), y, Math.fma(mat.m32(), z, mat.m33() * w)));
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat with this Vector4f and store the result in
+ * this
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @return this
+ */
+ public Vector4f mul(Matrix4x3fc mat) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ this.w = w;
+ return this;
+ }
+
+ public Vector4f mul(Matrix4x3fc mat, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w)));
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w)));
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w)));
+ dest.w = w;
+ return dest;
+ }
+
+ public Vector4f mulProject(Matrix4fc mat, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ float invW = 1.0f / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ dest.w = 1.0f;
+ return dest;
+ }
+
+ /**
+ * Multiply the given matrix mat
with this Vector4f, perform perspective division.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @return this
+ */
+ public Vector4f mulProject(Matrix4fc mat) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ float invW = 1.0f / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ this.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ this.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ this.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ this.w = 1.0f;
+ return this;
+ }
+
+ public Vector3f mulProject(Matrix4fc mat, Vector3f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ float invW = 1.0f / Math.fma(mat.m03(), x, Math.fma(mat.m13(), y, Math.fma(mat.m23(), z, mat.m33() * w)));
+ dest.x = Math.fma(mat.m00(), x, Math.fma(mat.m10(), y, Math.fma(mat.m20(), z, mat.m30() * w))) * invW;
+ dest.y = Math.fma(mat.m01(), x, Math.fma(mat.m11(), y, Math.fma(mat.m21(), z, mat.m31() * w))) * invW;
+ dest.z = Math.fma(mat.m02(), x, Math.fma(mat.m12(), y, Math.fma(mat.m22(), z, mat.m32() * w))) * invW;
+ return dest;
+ }
+
+ /**
+ * Multiply all components of this {@link Vector4f} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to multiply by
+ * @return this
+ */
+ public Vector4f mul(float scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ this.z = z * scalar;
+ this.w = w * scalar;
+ return this;
+ }
+
+ public Vector4f mul(float scalar, Vector4f dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ dest.z = z * scalar;
+ dest.w = w * scalar;
+ return dest;
+ }
+
+ /**
+ * Multiply the components of this Vector4f by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to multiply by
+ * @param y
+ * the y component to multiply by
+ * @param z
+ * the z component to multiply by
+ * @param w
+ * the w component to multiply by
+ * @return this
+ */
+ public Vector4f mul(float x, float y, float z, float w) {
+ this.x = this.x * x;
+ this.y = this.y * y;
+ this.z = this.z * z;
+ this.w = this.w * w;
+ return this;
+ }
+
+ public Vector4f mul(float x, float y, float z, float w, Vector4f dest) {
+ dest.x = this.x * x;
+ dest.y = this.y * y;
+ dest.z = this.z * z;
+ dest.w = this.w * w;
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector4f} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector4f div(float scalar) {
+ float inv = 1.0f / scalar;
+ this.x = x * inv;
+ this.y = y * inv;
+ this.z = z * inv;
+ this.w = w * inv;
+ return this;
+ }
+
+ public Vector4f div(float scalar, Vector4f dest) {
+ float inv = 1.0f / scalar;
+ dest.x = x * inv;
+ dest.y = y * inv;
+ dest.z = z * inv;
+ dest.w = w * inv;
+ return dest;
+ }
+
+ /**
+ * Divide the components of this Vector4f by the given scalar values and store the result in this
.
+ *
+ * @param x
+ * the x component to divide by
+ * @param y
+ * the y component to divide by
+ * @param z
+ * the z component to divide by
+ * @param w
+ * the w component to divide by
+ * @return this
+ */
+ public Vector4f div(float x, float y, float z, float w) {
+ this.x = this.x / x;
+ this.y = this.y / y;
+ this.z = this.z / z;
+ this.w = this.w / w;
+ return this;
+ }
+
+ public Vector4f div(float x, float y, float z, float w, Vector4f dest) {
+ dest.x = this.x / x;
+ dest.y = this.y / y;
+ dest.z = this.z / z;
+ dest.w = this.w / w;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector by the given quaternion quat
and store the result in this
.
+ *
+ * @see Quaternionf#transform(Vector4f)
+ *
+ * @param quat
+ * the quaternion to rotate this vector
+ * @return this
+ */
+ public Vector4f rotate(Quaternionfc quat) {
+ return quat.transform(this, this);
+ }
+
+ public Vector4f rotate(Quaternionfc quat, Vector4f dest) {
+ return quat.transform(this, dest);
+ }
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @param x
+ * the x component of the rotation axis
+ * @param y
+ * the y component of the rotation axis
+ * @param z
+ * the z component of the rotation axis
+ * @return this
+ */
+ public Vector4f rotateAbout(float angle, float x, float y, float z) {
+ if (y == 0.0f && z == 0.0f && Math.absEqualsOne(x))
+ return rotateX(x * angle, this);
+ else if (x == 0.0f && z == 0.0f && Math.absEqualsOne(y))
+ return rotateY(y * angle, this);
+ else if (x == 0.0f && y == 0.0f && Math.absEqualsOne(z))
+ return rotateZ(z * angle, this);
+ return rotateAxisInternal(angle, x, y, z, this);
+ }
+
+ public Vector4f rotateAxis(float angle, float aX, float aY, float aZ, Vector4f dest) {
+ if (aY == 0.0f && aZ == 0.0f && Math.absEqualsOne(aX))
+ return rotateX(aX * angle, dest);
+ else if (aX == 0.0f && aZ == 0.0f && Math.absEqualsOne(aY))
+ return rotateY(aY * angle, dest);
+ else if (aX == 0.0f && aY == 0.0f && Math.absEqualsOne(aZ))
+ return rotateZ(aZ * angle, dest);
+ return rotateAxisInternal(angle, aX, aY, aZ, dest);
+ }
+ private Vector4f rotateAxisInternal(float angle, float aX, float aY, float aZ, Vector4f dest) {
+ float hangle = angle * 0.5f;
+ float sinAngle = Math.sin(hangle);
+ float qx = aX * sinAngle, qy = aY * sinAngle, qz = aZ * sinAngle;
+ float qw = Math.cosFromSin(sinAngle, hangle);
+ float w2 = qw * qw, x2 = qx * qx, y2 = qy * qy, z2 = qz * qz, zw = qz * qw;
+ float xy = qx * qy, xz = qx * qz, yw = qy * qw, yz = qy * qz, xw = qx * qw;
+ float x = this.x, y = this.y, z = this.z;
+ dest.x = (w2 + x2 - z2 - y2) * x + (-zw + xy - zw + xy) * y + (yw + xz + xz + yw) * z;
+ dest.y = (xy + zw + zw + xy) * x + ( y2 - z2 + w2 - x2) * y + (yz + yz - xw - xw) * z;
+ dest.z = (xz - yw + xz - yw) * x + ( yz + yz + xw + xw) * y + (z2 - y2 - x2 + w2) * z;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the X axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector4f rotateX(float angle) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float y = this.y * cos - this.z * sin;
+ float z = this.y * sin + this.z * cos;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+
+ public Vector4f rotateX(float angle, Vector4f dest) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float y = this.y * cos - this.z * sin;
+ float z = this.y * sin + this.z * cos;
+ dest.x = this.x;
+ dest.y = y;
+ dest.z = z;
+ dest.w = this.w;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Y axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector4f rotateY(float angle) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos + this.z * sin;
+ float z = -this.x * sin + this.z * cos;
+ this.x = x;
+ this.z = z;
+ return this;
+ }
+
+ public Vector4f rotateY(float angle, Vector4f dest) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos + this.z * sin;
+ float z = -this.x * sin + this.z * cos;
+ dest.x = x;
+ dest.y = this.y;
+ dest.z = z;
+ dest.w = this.w;
+ return dest;
+ }
+
+ /**
+ * Rotate this vector the specified radians around the Z axis.
+ *
+ * @param angle
+ * the angle in radians
+ * @return this
+ */
+ public Vector4f rotateZ(float angle) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos - this.y * sin;
+ float y = this.x * sin + this.y * cos;
+ this.x = x;
+ this.y = y;
+ return this;
+ }
+
+ public Vector4f rotateZ(float angle, Vector4f dest) {
+ float sin = Math.sin(angle), cos = Math.cosFromSin(sin, angle);
+ float x = this.x * cos - this.y * sin;
+ float y = this.x * sin + this.y * cos;
+ dest.x = x;
+ dest.y = y;
+ dest.z = this.z;
+ dest.w = this.w;
+ return dest;
+ }
+
+ public float lengthSquared() {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ /**
+ * Get the length squared of a 4-dimensional single-precision vector.
+ *
+ * @param x the vector's x component
+ * @param y the vector's y component
+ * @param z the vector's z component
+ * @param w the vector's w component
+ *
+ * @return the length squared of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static float lengthSquared(float x, float y, float z, float w) {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ /**
+ * Get the length squared of a 4-dimensional int vector.
+ *
+ * @param x the vector's x component
+ * @param y the vector's y component
+ * @param z the vector's z component
+ * @param w the vector's w component
+ *
+ * @return the length squared of the given vector
+ */
+ public static float lengthSquared(int x, int y, int z, int w) {
+ return Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ }
+
+ public float length() {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ }
+
+ /**
+ * Get the length of a 4-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ * @param w The vector's w component
+ *
+ * @return the length of the given vector
+ *
+ * @author F. Neurath
+ */
+ public static float length(float x, float y, float z, float w) {
+ return Math.sqrt(Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w))));
+ }
+
+ /**
+ * Normalizes this vector.
+ *
+ * @return this
+ */
+ public Vector4f normalize() {
+ float invLength = 1.0f / length();
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ this.w = w * invLength;
+ return this;
+ }
+
+ public Vector4f normalize(Vector4f dest) {
+ float invLength = 1.0f / length();
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ dest.w = w * invLength;
+ return dest;
+ }
+
+ /**
+ * Scale this vector to have the given length.
+ *
+ * @param length
+ * the desired length
+ * @return this
+ */
+ public Vector4f normalize(float length) {
+ float invLength = 1.0f / length() * length;
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ this.w = w * invLength;
+ return this;
+ }
+
+ public Vector4f normalize(float length, Vector4f dest) {
+ float invLength = 1.0f / length() * length;
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ dest.w = w * invLength;
+ return dest;
+ }
+
+ /**
+ * Normalize this vector by computing only the norm of (x, y, z)
.
+ *
+ * @return this
+ */
+ public Vector4f normalize3() {
+ float invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ this.x = x * invLength;
+ this.y = y * invLength;
+ this.z = z * invLength;
+ this.w = w * invLength;
+ return this;
+ }
+
+ public Vector4f normalize3(Vector4f dest) {
+ float invLength = Math.invsqrt(Math.fma(x, x, Math.fma(y, y, z * z)));
+ dest.x = x * invLength;
+ dest.y = y * invLength;
+ dest.z = z * invLength;
+ dest.w = w * invLength;
+ return dest;
+ }
+
+ public float distance(Vector4fc v) {
+ float dx = this.x - v.x();
+ float dy = this.y - v.y();
+ float dz = this.z - v.z();
+ float dw = this.w - v.w();
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ public float distance(float x, float y, float z, float w) {
+ float dx = this.x - x;
+ float dy = this.y - y;
+ float dz = this.z - z;
+ float dw = this.w - w;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ public float distanceSquared(Vector4fc v) {
+ float dx = this.x - v.x();
+ float dy = this.y - v.y();
+ float dz = this.z - v.z();
+ float dw = this.w - v.w();
+ return Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw)));
+ }
+
+ public float distanceSquared(float x, float y, float z, float w) {
+ float dx = this.x - x;
+ float dy = this.y - y;
+ float dz = this.z - z;
+ float dw = this.w - w;
+ return Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw)));
+ }
+
+ /**
+ * Return the distance between (x1, y1, z1, w1)
and (x2, y2, z2, w2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param w1
+ * the w component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @param w2
+ * the 2 component of the second vector
+ * @return the euclidean distance
+ */
+ public static float distance(float x1, float y1, float z1, float w1, float x2, float y2, float z2, float w2) {
+ float dx = x1 - x2;
+ float dy = y1 - y2;
+ float dz = z1 - z2;
+ float dw = w1 - w2;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ /**
+ * Return the squared distance between (x1, y1, z1, w1)
and (x2, y2, z2, w2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param w1
+ * the w component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @param w2
+ * the w component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static float distanceSquared(float x1, float y1, float z1, float w1, float x2, float y2, float z2, float w2) {
+ float dx = x1 - x2;
+ float dy = y1 - y2;
+ float dz = z1 - z2;
+ float dw = w1 - w2;
+ return Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw)));
+ }
+
+ public float dot(Vector4fc v) {
+ return Math.fma(this.x, v.x(), Math.fma(this.y, v.y(), Math.fma(this.z, v.z(), this.w * v.w())));
+ }
+
+ public float dot(float x, float y, float z, float w) {
+ return Math.fma(this.x, x, Math.fma(this.y, y, Math.fma(this.z, z, this.w * w)));
+ }
+
+ public float angleCos(Vector4fc v) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ float length1Squared = Math.fma(x, x, Math.fma(y, y, Math.fma(z, z, w * w)));
+ float length2Squared = Math.fma(v.x(), v.x(), Math.fma(v.y(), v.y(), Math.fma(v.z(), v.z(), v.w() * v.w())));
+ float dot = Math.fma(x, v.x(), Math.fma(y, v.y(), Math.fma(z, v.z(), w * v.w())));
+ return dot / Math.sqrt(length1Squared * length2Squared);
+ }
+
+ public float angle(Vector4fc v) {
+ float cos = angleCos(v);
+ // This is because sometimes cos goes above 1 or below -1 because of lost precision
+ cos = cos < 1 ? cos : 1;
+ cos = cos > -1 ? cos : -1;
+ return Math.acos(cos);
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector4f zero() {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 0;
+ return this;
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector4f negate() {
+ this.x = -x;
+ this.y = -y;
+ this.z = -z;
+ this.w = -w;
+ return this;
+ }
+
+ public Vector4f negate(Vector4f dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ dest.w = -w;
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + Runtime.format(x, formatter) + " " + Runtime.format(y, formatter) + " " + Runtime.format(z, formatter) + " " + Runtime.format(w, formatter) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeFloat(x);
+ out.writeFloat(y);
+ out.writeFloat(z);
+ out.writeFloat(w);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ this.set(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4f min(Vector4fc v) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ this.z = z < v.z() ? z : v.z();
+ this.w = w < v.w() ? w : v.w();
+ return this;
+ }
+
+ public Vector4f min(Vector4fc v, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ dest.z = z < v.z() ? z : v.z();
+ dest.w = w < v.w() ? w : v.w();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4f max(Vector4fc v) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ this.z = z > v.z() ? z : v.z();
+ this.w = w > v.w() ? w : v.w();
+ return this;
+ }
+
+ public Vector4f max(Vector4fc v, Vector4f dest) {
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ dest.z = z > v.z() ? z : v.z();
+ dest.w = w > v.w() ? w : v.w();
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Float.floatToIntBits(w);
+ result = prime * result + Float.floatToIntBits(x);
+ result = prime * result + Float.floatToIntBits(y);
+ result = prime * result + Float.floatToIntBits(z);
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Vector4f other = (Vector4f) obj;
+ if (Float.floatToIntBits(w) != Float.floatToIntBits(other.w))
+ return false;
+ if (Float.floatToIntBits(x) != Float.floatToIntBits(other.x))
+ return false;
+ if (Float.floatToIntBits(y) != Float.floatToIntBits(other.y))
+ return false;
+ if (Float.floatToIntBits(z) != Float.floatToIntBits(other.z))
+ return false;
+ return true;
+ }
+
+ public boolean equals(Vector4fc v, float delta) {
+ if (this == v)
+ return true;
+ if (v == null)
+ return false;
+ if (!(v instanceof Vector4fc))
+ return false;
+ if (!Runtime.equals(x, v.x(), delta))
+ return false;
+ if (!Runtime.equals(y, v.y(), delta))
+ return false;
+ if (!Runtime.equals(z, v.z(), delta))
+ return false;
+ if (!Runtime.equals(w, v.w(), delta))
+ return false;
+ return true;
+ }
+
+ public boolean equals(float x, float y, float z, float w) {
+ if (Float.floatToIntBits(this.x) != Float.floatToIntBits(x))
+ return false;
+ if (Float.floatToIntBits(this.y) != Float.floatToIntBits(y))
+ return false;
+ if (Float.floatToIntBits(this.z) != Float.floatToIntBits(z))
+ return false;
+ if (Float.floatToIntBits(this.w) != Float.floatToIntBits(w))
+ return false;
+ return true;
+ }
+
+ public Vector4f smoothStep(Vector4fc v, float t, Vector4f dest) {
+ float t2 = t * t;
+ float t3 = t2 * t;
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = (x + x - v.x() - v.x()) * t3 + (3.0f * v.x() - 3.0f * x) * t2 + x * t + x;
+ dest.y = (y + y - v.y() - v.y()) * t3 + (3.0f * v.y() - 3.0f * y) * t2 + y * t + y;
+ dest.z = (z + z - v.z() - v.z()) * t3 + (3.0f * v.z() - 3.0f * z) * t2 + z * t + z;
+ dest.w = (w + w - v.w() - v.w()) * t3 + (3.0f * v.w() - 3.0f * w) * t2 + w * t + w;
+ return dest;
+ }
+
+ public Vector4f hermite(Vector4fc t0, Vector4fc v1, Vector4fc t1, float t, Vector4f dest) {
+ float t2 = t * t;
+ float t3 = t2 * t;
+ float x = this.x, y = this.y, z = this.z, w = this.w;
+ dest.x = (x + x - v1.x() - v1.x() + t1.x() + t0.x()) * t3 + (3.0f * v1.x() - 3.0f * x - t0.x() - t0.x() - t1.x()) * t2 + x * t + x;
+ dest.y = (y + y - v1.y() - v1.y() + t1.y() + t0.y()) * t3 + (3.0f * v1.y() - 3.0f * y - t0.y() - t0.y() - t1.y()) * t2 + y * t + y;
+ dest.z = (z + z - v1.z() - v1.z() + t1.z() + t0.z()) * t3 + (3.0f * v1.z() - 3.0f * z - t0.z() - t0.z() - t1.z()) * t2 + z * t + z;
+ dest.w = (w + w - v1.w() - v1.w() + t1.w() + t0.w()) * t3 + (3.0f * v1.w() - 3.0f * w - t0.w() - t0.w() - t1.w()) * t2 + w * t + w;
+ return dest;
+ }
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in this
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @return this
+ */
+ public Vector4f lerp(Vector4fc other, float t) {
+ this.x = Math.fma(other.x() - x, t, x);
+ this.y = Math.fma(other.y() - y, t, y);
+ this.z = Math.fma(other.z() - z, t, z);
+ this.w = Math.fma(other.w() - w, t, w);
+ return this;
+ }
+
+ public Vector4f lerp(Vector4fc other, float t, Vector4f dest) {
+ dest.x = Math.fma(other.x() - x, t, x);
+ dest.y = Math.fma(other.y() - y, t, y);
+ dest.z = Math.fma(other.z() - z, t, z);
+ dest.w = Math.fma(other.w() - w, t, w);
+ return dest;
+ }
+
+ public float get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Vector4i get(int mode, Vector4i dest) {
+ dest.x = Math.roundUsing(this.x(), mode);
+ dest.y = Math.roundUsing(this.y(), mode);
+ dest.z = Math.roundUsing(this.z(), mode);
+ dest.w = Math.roundUsing(this.w(), mode);
+ return dest;
+ }
+
+ public Vector4f get(Vector4f dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ dest.z = this.z();
+ dest.w = this.w();
+ return dest;
+ }
+
+ public Vector4d get(Vector4d dest) {
+ dest.x = this.x();
+ dest.y = this.y();
+ dest.z = this.z();
+ dest.w = this.w();
+ return dest;
+ }
+
+ public int maxComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ float absZ = Math.abs(z);
+ float absW = Math.abs(w);
+ if (absX >= absY && absX >= absZ && absX >= absW) {
+ return 0;
+ } else if (absY >= absZ && absY >= absW) {
+ return 1;
+ } else if (absZ >= absW) {
+ return 2;
+ }
+ return 3;
+ }
+
+ public int minComponent() {
+ float absX = Math.abs(x);
+ float absY = Math.abs(y);
+ float absZ = Math.abs(z);
+ float absW = Math.abs(w);
+ if (absX < absY && absX < absZ && absX < absW) {
+ return 0;
+ } else if (absY < absZ && absY < absW) {
+ return 1;
+ } else if (absZ < absW) {
+ return 2;
+ }
+ return 3;
+ }
+
+ /**
+ * Set each component of this vector to the largest (closest to positive
+ * infinity) {@code float} value that is less than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector4f floor() {
+ this.x = Math.floor(x);
+ this.y = Math.floor(y);
+ this.z = Math.floor(z);
+ this.w = Math.floor(w);
+ return this;
+ }
+
+ public Vector4f floor(Vector4f dest) {
+ dest.x = Math.floor(x);
+ dest.y = Math.floor(y);
+ dest.z = Math.floor(z);
+ dest.w = Math.floor(w);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the smallest (closest to negative
+ * infinity) {@code float} value that is greater than or equal to that
+ * component and is equal to a mathematical integer.
+ *
+ * @return this
+ */
+ public Vector4f ceil() {
+ this.x = Math.ceil(x);
+ this.y = Math.ceil(y);
+ this.z = Math.ceil(z);
+ this.w = Math.ceil(w);
+ return this;
+ }
+
+ public Vector4f ceil(Vector4f dest) {
+ dest.x = Math.ceil(x);
+ dest.y = Math.ceil(y);
+ dest.z = Math.ceil(z);
+ dest.w = Math.ceil(w);
+ return dest;
+ }
+
+ /**
+ * Set each component of this vector to the closest float that is equal to
+ * a mathematical integer, with ties rounding to positive infinity.
+ *
+ * @return this
+ */
+ public Vector4f round() {
+ this.x = Math.round(x);
+ this.y = Math.round(y);
+ this.z = Math.round(z);
+ this.w = Math.round(w);
+ return this;
+ }
+
+ public Vector4f round(Vector4f dest) {
+ dest.x = Math.round(x);
+ dest.y = Math.round(y);
+ dest.z = Math.round(z);
+ dest.w = Math.round(w);
+ return dest;
+ }
+
+ public boolean isFinite() {
+ return Math.isFinite(x) && Math.isFinite(y) && Math.isFinite(z) && Math.isFinite(w);
+ }
+
+ /**
+ * Compute the absolute of each of this vector's components.
+ *
+ * @return this
+ */
+ public Vector4f absolute() {
+ this.x = Math.abs(x);
+ this.y = Math.abs(y);
+ this.z = Math.abs(z);
+ this.w = Math.abs(w);
+ return this;
+ }
+
+ public Vector4f absolute(Vector4f dest) {
+ dest.x = Math.abs(x);
+ dest.y = Math.abs(y);
+ dest.z = Math.abs(z);
+ dest.w = Math.abs(w);
+ return dest;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4fc.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4fc.java
new file mode 100644
index 000000000..31a8e9507
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4fc.java
@@ -0,0 +1,838 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.util.*;
+
+/**
+ * Interface to a read-only view of a 4-dimensional vector of single-precision floats.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector4fc {
+
+ /**
+ * @return the value of the x component
+ */
+ float x();
+
+ /**
+ * @return the value of the y component
+ */
+ float y();
+
+ /**
+ * @return the value of the z component
+ */
+ float z();
+
+ /**
+ * @return the value of the w component
+ */
+ float w();
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} at the current
+ * buffer {@link FloatBuffer#position() position}.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * In order to specify the offset into the FloatBuffer at which
+ * the vector is stored, use {@link #get(int, FloatBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ * @see #get(int, FloatBuffer)
+ */
+ FloatBuffer get(FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link FloatBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given FloatBuffer.
+ *
+ * @param index
+ * the absolute position into the FloatBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ FloatBuffer get(int index, FloatBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which
+ * the vector is stored, use {@link #get(int, ByteBuffer)}, taking
+ * the absolute position as parameter.
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ * @see #get(int, ByteBuffer)
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the specified
+ * absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector4fc getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to subtract from this
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f sub(Vector4fc v, Vector4f dest);
+
+ /**
+ * Subtract (x, y, z, w)
from this and store the result in dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f sub(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f add(Vector4fc v, Vector4f dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param w
+ * the w component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f add(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f fma(Vector4fc a, Vector4fc b, Vector4f dest);
+
+ /**
+ * Add the component-wise multiplication of a * b
to this vector
+ * and store the result in dest
.
+ *
+ * @param a
+ * the first multiplicand
+ * @param b
+ * the second multiplicand
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f fma(float a, Vector4fc b, Vector4f dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f mulAdd(Vector4fc a, Vector4fc b, Vector4f dest);
+
+ /**
+ * Add the component-wise multiplication of this * a
to b
+ * and store the result in dest
.
+ *
+ * @param a
+ * the multiplicand
+ * @param b
+ * the addend
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f mulAdd(float a, Vector4fc b, Vector4f dest);
+
+ /**
+ * Multiply this Vector4f component-wise by another Vector4f and store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f mul(Vector4fc v, Vector4f dest);
+
+ /**
+ * Divide this Vector4f component-wise by another Vector4f and store the result in dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f div(Vector4fc v, Vector4f dest);
+
+ /**
+ * Multiply the given matrix mat with this Vector4f and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4f mul(Matrix4fc mat, Vector4f dest);
+
+ /**
+ * Multiply the transpose of the given matrix mat
with this Vector4f and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the matrix whose transpose to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4f mulTranspose(Matrix4fc mat, Vector4f dest);
+
+ /**
+ * Multiply the given affine matrix mat with this Vector4f and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the affine matrix to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4f mulAffine(Matrix4fc mat, Vector4f dest);
+
+ /**
+ * Multiply the transpose of the given affine matrix mat
with this Vector4f and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the affine matrix whose transpose to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4f mulAffineTranspose(Matrix4fc mat, Vector4f dest);
+
+ /**
+ * Multiply the given matrix mat with this Vector4f and store the result in
+ * dest
.
+ *
+ * @param mat
+ * the matrix to multiply the vector with
+ * @param dest
+ * the destination vector to hold the result
+ * @return dest
+ */
+ Vector4f mul(Matrix4x3fc mat, Vector4f dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector4f, perform perspective division
+ * and store the result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f mulProject(Matrix4fc mat, Vector4f dest);
+
+ /**
+ * Multiply the given matrix mat
with this Vector4f, perform perspective division
+ * and store the (x, y, z)
result in dest
.
+ *
+ * @param mat
+ * the matrix to multiply this vector by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector3f mulProject(Matrix4fc mat, Vector3f dest);
+
+ /**
+ * Multiply all components of this {@link Vector4f} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f mul(float scalar, Vector4f dest);
+
+ /**
+ * Multiply the components of this Vector4f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to multiply by
+ * @param y
+ * the y component to multiply by
+ * @param z
+ * the z component to multiply by
+ * @param w
+ * the w component to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f mul(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Divide all components of this {@link Vector4f} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f div(float scalar, Vector4f dest);
+
+ /**
+ * Divide the components of this Vector4f by the given scalar values and store the result in dest
.
+ *
+ * @param x
+ * the x component to divide by
+ * @param y
+ * the y component to divide by
+ * @param z
+ * the z component to divide by
+ * @param w
+ * the w component to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f div(float x, float y, float z, float w, Vector4f dest);
+
+ /**
+ * Rotate this vector by the given quaternion quat
and store the result in dest
.
+ *
+ * @see Quaternionf#transform(Vector4f)
+ *
+ * @param quat
+ * the quaternion to rotate this vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f rotate(Quaternionfc quat, Vector4f dest);
+
+ /**
+ * Rotate this vector the specified radians around the given rotation axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param aX
+ * the x component of the rotation axis
+ * @param aY
+ * the y component of the rotation axis
+ * @param aZ
+ * the z component of the rotation axis
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f rotateAxis(float angle, float aX, float aY, float aZ, Vector4f dest);
+
+ /**
+ * Rotate this vector the specified radians around the X axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f rotateX(float angle, Vector4f dest);
+
+ /**
+ * Rotate this vector the specified radians around the Y axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f rotateY(float angle, Vector4f dest);
+
+ /**
+ * Rotate this vector the specified radians around the Z axis and store the result
+ * into dest
.
+ *
+ * @param angle
+ * the angle in radians
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f rotateZ(float angle, Vector4f dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ float lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ float length();
+
+ /**
+ * Normalizes this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f normalize(Vector4f dest);
+
+ /**
+ * Scale this vector to have the given length and store the result in dest
.
+ *
+ * @param length
+ * the desired length
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f normalize(float length, Vector4f dest);
+
+ /**
+ * Normalize this vector by computing only the norm of (x, y, z)
and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f normalize3(Vector4f dest);
+
+ /**
+ * Return the distance between this Vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ float distance(Vector4fc v);
+
+ /**
+ * Return the distance between this
vector and (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the euclidean distance
+ */
+ float distance(float x, float y, float z, float w);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ float distanceSquared(Vector4fc v);
+
+ /**
+ * Return the square of the distance between this
vector and
+ * (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the square of the distance
+ */
+ float distanceSquared(float x, float y, float z, float w);
+
+ /**
+ * Compute the dot product (inner product) of this vector and v
+ * .
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ float dot(Vector4fc v);
+
+ /**
+ * Compute the dot product (inner product) of this vector and (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the dot product
+ */
+ float dot(float x, float y, float z, float w);
+
+ /**
+ * Return the cosine of the angle between this vector and the supplied vector. Use this instead of Math.cos(angle(v))
.
+ *
+ * @see #angle(Vector4fc)
+ *
+ * @param v
+ * the other vector
+ * @return the cosine of the angle
+ */
+ float angleCos(Vector4fc v);
+
+ /**
+ * Return the angle between this vector and the supplied vector.
+ *
+ * @see #angleCos(Vector4fc)
+ *
+ * @param v
+ * the other vector
+ * @return the angle, in radians
+ */
+ float angle(Vector4fc v);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f negate(Vector4f dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f min(Vector4fc v, Vector4f dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f max(Vector4fc v, Vector4f dest);
+
+ /**
+ * Linearly interpolate this
and other
using the given interpolation factor t
+ * and store the result in dest
.
+ *
+ * If t
is 0.0
then the result is this
. If the interpolation factor is 1.0
+ * then the result is other
.
+ *
+ * @param other
+ * the other vector
+ * @param t
+ * the interpolation factor between 0.0 and 1.0
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f lerp(Vector4fc other, float t, Vector4f dest);
+
+ /**
+ * Compute a smooth-step (i.e. hermite with zero tangents) interpolation
+ * between this
vector and the given vector v
and
+ * store the result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f smoothStep(Vector4fc v, float t, Vector4f dest);
+
+ /**
+ * Compute a hermite interpolation between this
vector and its
+ * associated tangent t0
and the given vector v
+ * with its tangent t1
and store the result in
+ * dest
.
+ *
+ * @param t0
+ * the tangent of this
vector
+ * @param v1
+ * the other vector
+ * @param t1
+ * the tangent of the other vector
+ * @param t
+ * the interpolation factor, within [0..1]
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f hermite(Vector4fc t0, Vector4fc v1, Vector4fc t1, float t, Vector4f dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..3]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..3]
+ */
+ float get(int component) throws IllegalArgumentException;
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector
+ * using the given {@link RoundingMode}.
+ *
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i get(int mode, Vector4i dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f get(Vector4f dest);
+
+ /**
+ * Set the components of the given vector dest
to those of this
vector.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4d get(Vector4d dest);
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..3]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..3]
+ */
+ int minComponent();
+
+ /**
+ * Compute for each component of this vector the largest (closest to positive
+ * infinity) {@code float} value that is less than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f floor(Vector4f dest);
+
+ /**
+ * Compute for each component of this vector the smallest (closest to negative
+ * infinity) {@code float} value that is greater than or equal to that
+ * component and is equal to a mathematical integer and store the result in
+ * dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f ceil(Vector4f dest);
+
+ /**
+ * Compute for each component of this vector the closest float that is equal to
+ * a mathematical integer, with ties rounding to positive infinity and store
+ * the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f round(Vector4f dest);
+
+ /**
+ * Determine whether all components are finite floating-point values, that
+ * is, they are not {@link Float#isNaN() NaN} and not
+ * {@link Float#isInfinite() infinity}.
+ *
+ * @return {@code true} if all components are finite floating-point values;
+ * {@code false} otherwise
+ */
+ boolean isFinite();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4f absolute(Vector4f dest);
+
+ /**
+ * Compare the vector components of this
vector with the given vector using the given delta
+ * and return whether all of them are equal within a maximum difference of delta
.
+ *
+ * Please note that this method is not used by any data structure such as {@link ArrayList} {@link HashSet} or {@link HashMap}
+ * and their operations, such as {@link ArrayList#contains(Object)} or {@link HashSet#remove(Object)}, since those
+ * data structures only use the {@link Object#equals(Object)} and {@link Object#hashCode()} methods.
+ *
+ * @param v
+ * the other vector
+ * @param delta
+ * the allowed maximum difference
+ * @return true
whether all of the vector components are equal; false
otherwise
+ */
+ boolean equals(Vector4fc v, float delta);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y, z, w)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @param w
+ * the w component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(float x, float y, float z, float w);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4i.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4i.java
new file mode 100644
index 000000000..8749284b9
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4i.java
@@ -0,0 +1,1212 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2015-2021 Richard Greenlees
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * Contains the definition of a Vector comprising 4 ints and associated
+ * transformations.
+ *
+ * @author Richard Greenlees
+ * @author Kai Burjack
+ * @author Hans Uhlig
+ */
+public class Vector4i implements Externalizable, Cloneable, Vector4ic {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The x component of the vector.
+ */
+ public int x;
+ /**
+ * The y component of the vector.
+ */
+ public int y;
+ /**
+ * The z component of the vector.
+ */
+ public int z;
+ /**
+ * The w component of the vector.
+ */
+ public int w;
+
+ /**
+ * Create a new {@link Vector4i} of (0, 0, 0, 1)
.
+ */
+ public Vector4i() {
+ this.w = 1;
+ }
+
+ /**
+ * Create a new {@link Vector4i} with the same values as v
.
+ *
+ * @param v
+ * the {@link Vector4ic} to copy the values from
+ */
+ public Vector4i(Vector4ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ }
+
+ /**
+ * Create a new {@link Vector4i} with the first three components from the
+ * given v
and the given w
.
+ *
+ * @param v
+ * the {@link Vector3ic}
+ * @param w
+ * the w component
+ */
+ public Vector4i(Vector3ic v, int w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4i} with the first two components from the
+ * given v
and the given z
, and w
.
+ *
+ * @param v
+ * the {@link Vector2ic}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4i(Vector2ic v, int z, int w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4i} with the first three components from the
+ * given v
and the given w
and round using the given {@link RoundingMode}.
+ *
+ * @param v
+ * the {@link Vector3fc} to copy the values from
+ * @param w
+ * the w component
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector4i(Vector3fc v, float w, int mode) {
+ x = Math.roundUsing(v.x(), mode);
+ y = Math.roundUsing(v.y(), mode);
+ z = Math.roundUsing(v.z(), mode);
+ w = Math.roundUsing(w, mode);
+ }
+
+ /**
+ * Create a new {@link Vector4i} and initialize its components to the rounded value of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector4fc} to round and copy the values from
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector4i(Vector4fc v, int mode) {
+ x = Math.roundUsing(v.x(), mode);
+ y = Math.roundUsing(v.y(), mode);
+ z = Math.roundUsing(v.z(), mode);
+ w = Math.roundUsing(v.w(), mode);
+ }
+
+ /**
+ * Create a new {@link Vector4i} and initialize its components to the rounded value of
+ * the given vector.
+ *
+ * @param v
+ * the {@link Vector4dc} to round and copy the values from
+ * @param mode
+ * the {@link RoundingMode} to use
+ */
+ public Vector4i(Vector4dc v, int mode) {
+ x = Math.roundUsing(v.x(), mode);
+ y = Math.roundUsing(v.y(), mode);
+ z = Math.roundUsing(v.z(), mode);
+ w = Math.roundUsing(v.w(), mode);
+ }
+
+ /**
+ * Create a new {@link Vector4i} and initialize all four components with the
+ * given value.
+ *
+ * @param s
+ * scalar value of all four components
+ */
+ public Vector4i(int s) {
+ this.x = s;
+ this.y = s;
+ this.z = s;
+ this.w = s;
+ }
+
+ /**
+ * Create a new {@link Vector4i} with the given component values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ */
+ public Vector4i(int x, int y, int z, int w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /**
+ * Create a new {@link Vector4i} and initialize its four components from the first
+ * four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ */
+ public Vector4i(int[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ }
+
+ /**
+ * Create a new {@link Vector4i} and read this vector from the supplied
+ * {@link ByteBuffer} at the current buffer
+ * {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * read, use {@link #Vector4i(int, ByteBuffer)}, taking the absolute
+ * position as parameter.
+ *
+ * @see #Vector4i(int, ByteBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ */
+ public Vector4i(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4i} and read this vector from the supplied
+ * {@link ByteBuffer} starting at the specified absolute buffer
+ * position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ */
+ public Vector4i(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4i} and read this vector from the supplied
+ * {@link IntBuffer} at the current buffer
+ * {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * read, use {@link #Vector4i(int, IntBuffer)}, taking the absolute position
+ * as parameter.
+ *
+ * @see #Vector4i(int, IntBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ */
+ public Vector4i(IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ }
+
+ /**
+ * Create a new {@link Vector4i} and read this vector from the supplied
+ * {@link IntBuffer} starting at the specified absolute buffer
+ * position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ */
+ public Vector4i(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ }
+
+ public int x() {
+ return this.x;
+ }
+
+ public int y() {
+ return this.y;
+ }
+
+ public int z() {
+ return this.z;
+ }
+
+ public int w() {
+ return this.w;
+ }
+
+ /**
+ * Set this {@link Vector4i} to the values of the given v
.
+ *
+ * @param v
+ * the vector whose values will be copied into this
+ * @return this
+ */
+ public Vector4i set(Vector4ic v) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = v.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4i} to the values of v using {@link RoundingMode#TRUNCATE} rounding.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @return this
+ */
+ public Vector4i set(Vector4dc v) {
+ this.x = (int) v.x();
+ this.y = (int) v.y();
+ this.z = (int) v.z();
+ this.w = (int) v.w();
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4i} to the values of v using the given {@link RoundingMode}.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @return this
+ */
+ public Vector4i set(Vector4dc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(v.z(), mode);
+ this.w = Math.roundUsing(v.w(), mode);
+ return this;
+ }
+
+ /**
+ * Set this {@link Vector4i} to the values of v using the given {@link RoundingMode}.
+ *
+ * Note that due to the given vector v
storing the components
+ * in double-precision, there is the possibility to lose precision.
+ *
+ * @param v
+ * the vector to copy from
+ * @param mode
+ * the {@link RoundingMode} to use
+ * @return this
+ */
+ public Vector4i set(Vector4fc v, int mode) {
+ this.x = Math.roundUsing(v.x(), mode);
+ this.y = Math.roundUsing(v.y(), mode);
+ this.z = Math.roundUsing(v.z(), mode);
+ this.w = Math.roundUsing(v.w(), mode);
+ return this;
+ }
+
+ /**
+ * Set the first three components of this to the components of
+ * v
and the last component to w
.
+ *
+ * @param v
+ * the {@link Vector3ic} to copy
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4i set(Vector3ic v, int w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = v.z();
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Sets the first two components of this to the components of given
+ * v
and last two components to the given z
, and
+ * w
.
+ *
+ * @param v
+ * the {@link Vector2ic}
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4i set(Vector2ic v, int z, int w) {
+ this.x = v.x();
+ this.y = v.y();
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied value.
+ *
+ * @param s
+ * the value of all four components
+ * @return this
+ */
+ public Vector4i set(int s) {
+ this.x = s;
+ this.y = s;
+ this.z = s;
+ this.w = s;
+ return this;
+ }
+
+ /**
+ * Set the x, y, z, and w components to the supplied values.
+ *
+ * @param x
+ * the x component
+ * @param y
+ * the y component
+ * @param z
+ * the z component
+ * @param w
+ * the w component
+ * @return this
+ */
+ public Vector4i set(int x, int y, int z, int w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ }
+
+ /**
+ * Set the four components of this vector to the first four elements of the given array.
+ *
+ * @param xyzw
+ * the array containing at least four elements
+ * @return this
+ */
+ public Vector4i set(int[] xyzw) {
+ this.x = xyzw[0];
+ this.y = xyzw[1];
+ this.z = xyzw[2];
+ this.w = xyzw[3];
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * read, use {@link #set(int, ByteBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #set(int, ByteBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4i set(ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link ByteBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4i set(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link IntBuffer} at the current
+ * buffer {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * read, use {@link #set(int, IntBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #set(int, IntBuffer)
+ *
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4i set(IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, buffer.position(), buffer);
+ return this;
+ }
+
+ /**
+ * Read this vector from the supplied {@link IntBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * values will be read in x, y, z, w
order
+ * @return this
+ */
+ public Vector4i set(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.get(this, index, buffer);
+ return this;
+ }
+
+ /**
+ * Set the values of this vector by reading 4 integer values from off-heap memory,
+ * starting at the given address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap memory address to read the vector values from
+ * @return this
+ */
+ public Vector4i setFromAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.get(this, address);
+ return this;
+ }
+
+ public int get(int component) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public int maxComponent() {
+ int absX = Math.abs(x);
+ int absY = Math.abs(y);
+ int absZ = Math.abs(z);
+ int absW = Math.abs(w);
+ if (absX >= absY && absX >= absZ && absX >= absW) {
+ return 0;
+ } else if (absY >= absZ && absY >= absW) {
+ return 1;
+ } else if (absZ >= absW) {
+ return 2;
+ }
+ return 3;
+ }
+
+ public int minComponent() {
+ int absX = Math.abs(x);
+ int absY = Math.abs(y);
+ int absZ = Math.abs(z);
+ int absW = Math.abs(w);
+ if (absX < absY && absX < absZ && absX < absW) {
+ return 0;
+ } else if (absY < absZ && absY < absW) {
+ return 1;
+ } else if (absZ < absW) {
+ return 2;
+ }
+ return 3;
+ }
+
+ /**
+ * Set the value of the specified component of this vector.
+ *
+ * @param component
+ * the component whose value to set, within [0..3]
+ * @param value
+ * the value to set
+ * @return this
+ * @throws IllegalArgumentException if component
is not within [0..3]
+ */
+ public Vector4i setComponent(int component, int value) throws IllegalArgumentException {
+ switch (component) {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ public IntBuffer get(IntBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public IntBuffer get(int index, IntBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, buffer.position(), buffer);
+ return buffer;
+ }
+
+ public ByteBuffer get(int index, ByteBuffer buffer) {
+ MemUtil.INSTANCE.put(this, index, buffer);
+ return buffer;
+ }
+
+ public Vector4ic getToAddress(long address) {
+ if (Options.NO_UNSAFE)
+ throw new UnsupportedOperationException("Not supported when using joml.nounsafe");
+ MemUtil.MemUtilUnsafe.put(this, address);
+ return this;
+ }
+
+ /**
+ * Subtract the supplied vector from this one.
+ *
+ * @param v
+ * the vector to subtract
+ * @return this
+ */
+ public Vector4i sub(Vector4ic v) {
+ this.x = this.x - v.x();
+ this.y = this.y - v.y();
+ this.z = this.z - v.z();
+ this.w = this.w - v.w();
+ return this;
+ }
+
+ /**
+ * Subtract (x, y, z, w)
from this.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @return this
+ */
+ public Vector4i sub(int x, int y, int z, int w) {
+ this.x = this.x - x;
+ this.y = this.y - y;
+ this.z = this.z - z;
+ this.w = this.w - w;
+ return this;
+ }
+
+ public Vector4i sub(Vector4ic v, Vector4i dest) {
+ dest.x = this.x - v.x();
+ dest.y = this.y - v.y();
+ dest.z = this.z - v.z();
+ dest.w = this.w - v.w();
+ return dest;
+ }
+
+ public Vector4i sub(int x, int y, int z, int w, Vector4i dest) {
+ dest.x = this.x - x;
+ dest.y = this.y - y;
+ dest.z = this.z - z;
+ dest.w = this.w - w;
+ return dest;
+ }
+
+ /**
+ * Add the supplied vector to this one.
+ *
+ * @param v
+ * the vector to add
+ * @return this
+ */
+ public Vector4i add(Vector4ic v) {
+ this.x = this.x + v.x();
+ this.y = this.y + v.y();
+ this.z = this.z + v.z();
+ this.w = this.w + v.w();
+ return this;
+ }
+
+ public Vector4i add(Vector4ic v, Vector4i dest) {
+ dest.x = this.x + v.x();
+ dest.y = this.y + v.y();
+ dest.z = this.z + v.z();
+ dest.w = this.w + v.w();
+ return dest;
+ }
+
+ /**
+ * Increment the components of this vector by the given values.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param w
+ * the w component to add
+ * @return this
+ */
+ public Vector4i add(int x, int y, int z, int w) {
+ this.x = this.x + x;
+ this.y = this.y + y;
+ this.z = this.z + z;
+ this.w = this.w + w;
+ return this;
+ }
+
+ public Vector4i add(int x, int y, int z, int w, Vector4i dest) {
+ dest.x = this.x + x;
+ dest.y = this.y + y;
+ dest.z = this.z + z;
+ dest.w = this.w + w;
+ return dest;
+ }
+
+ /**
+ * Multiply this Vector4i component-wise by another Vector4i.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4i mul(Vector4ic v) {
+ this.x = x * v.x();
+ this.y = y * v.y();
+ this.z = z * v.z();
+ this.w = w * v.w();
+ return this;
+ }
+
+ public Vector4i mul(Vector4ic v, Vector4i dest) {
+ dest.x = x * v.x();
+ dest.y = y * v.y();
+ dest.z = z * v.z();
+ dest.w = w * v.w();
+ return dest;
+ }
+
+ /**
+ * Divide this Vector4i component-wise by another Vector4i.
+ *
+ * @param v
+ * the vector to divide by
+ * @return this
+ */
+ public Vector4i div(Vector4ic v) {
+ this.x = x / v.x();
+ this.y = y / v.y();
+ this.z = z / v.z();
+ this.w = w / v.w();
+ return this;
+ }
+
+ public Vector4i div(Vector4ic v, Vector4i dest) {
+ dest.x = x / v.x();
+ dest.y = y / v.y();
+ dest.z = z / v.z();
+ dest.w = w / v.w();
+ return dest;
+ }
+
+ /**
+ * Multiply all components of this {@link Vector4i} by the given scalar
+ * value.
+ *
+ * @param scalar
+ * the scalar to multiply by
+ * @return this
+ */
+ public Vector4i mul(int scalar) {
+ this.x = x * scalar;
+ this.y = y * scalar;
+ this.z = z * scalar;
+ this.w = w * scalar;
+ return this;
+ }
+
+ public Vector4i mul(int scalar, Vector4i dest) {
+ dest.x = x * scalar;
+ dest.y = y * scalar;
+ dest.z = z * scalar;
+ dest.w = w * scalar;
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector3i} by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector4i div(float scalar) {
+ float invscalar = 1.0f / scalar;
+ this.x = (int) (x * invscalar);
+ this.y = (int) (y * invscalar);
+ this.z = (int) (z * invscalar);
+ this.w = (int) (w * invscalar);
+ return this;
+ }
+
+ public Vector4i div(float scalar, Vector4i dest) {
+ float invscalar = 1.0f / scalar;
+ dest.x = (int) (x * invscalar);
+ dest.y = (int) (y * invscalar);
+ dest.z = (int) (z * invscalar);
+ dest.w = (int) (w * invscalar);
+ return dest;
+ }
+
+ /**
+ * Divide all components of this {@link Vector4i} by the given scalar value.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @return this
+ */
+ public Vector4i div(int scalar) {
+ this.x = x / scalar;
+ this.y = y / scalar;
+ this.z = z / scalar;
+ this.w = w / scalar;
+ return this;
+ }
+
+ public Vector4i div(int scalar, Vector4i dest) {
+ dest.x = x / scalar;
+ dest.y = y / scalar;
+ dest.z = z / scalar;
+ dest.w = w / scalar;
+ return dest;
+ }
+
+ public long lengthSquared() {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ /**
+ * Get the length squared of a 4-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ * @param w The vector's w component
+ *
+ * @return the length squared of the given vector
+ */
+ public static long lengthSquared(int x, int y, int z, int w) {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ public double length() {
+ return Math.sqrt(x * x + y * y + z * z + w * w);
+ }
+
+ /**
+ * Get the length of a 4-dimensional single-precision vector.
+ *
+ * @param x The vector's x component
+ * @param y The vector's y component
+ * @param z The vector's z component
+ * @param w The vector's w component
+ *
+ * @return the length squared of the given vector
+ */
+ public static double length(int x, int y, int z, int w) {
+ return Math.sqrt(x * x + y * y + z * z + w * w);
+ }
+
+ public double distance(Vector4ic v) {
+ int dx = this.x - v.x();
+ int dy = this.y - v.y();
+ int dz = this.z - v.z();
+ int dw = this.w - v.w();
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ public double distance(int x, int y, int z, int w) {
+ int dx = this.x - x;
+ int dy = this.y - y;
+ int dz = this.z - z;
+ int dw = this.w - w;
+ return Math.sqrt(Math.fma(dx, dx, Math.fma(dy, dy, Math.fma(dz, dz, dw * dw))));
+ }
+
+ public long gridDistance(Vector4ic v) {
+ return Math.abs(v.x() - x()) + Math.abs(v.y() - y()) + Math.abs(v.z() - z()) + Math.abs(v.w() - w());
+ }
+
+ public long gridDistance(int x, int y, int z, int w) {
+ return Math.abs(x - x()) + Math.abs(y - y()) + Math.abs(z - z()) + Math.abs(w - w());
+ }
+
+ public int distanceSquared(Vector4ic v) {
+ int dx = this.x - v.x();
+ int dy = this.y - v.y();
+ int dz = this.z - v.z();
+ int dw = this.w - v.w();
+ return dx * dx + dy * dy + dz * dz + dw * dw;
+ }
+
+ public int distanceSquared(int x, int y, int z, int w) {
+ int dx = this.x - x;
+ int dy = this.y - y;
+ int dz = this.z - z;
+ int dw = this.w - w;
+ return dx * dx + dy * dy + dz * dz + dw * dw;
+ }
+
+ /**
+ * Return the distance between (x1, y1, z1, w1)
and (x2, y2, z2, w2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param w1
+ * the w component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @param w2
+ * the 2 component of the second vector
+ * @return the euclidean distance
+ */
+ public static double distance(int x1, int y1, int z1, int w1, int x2, int y2, int z2, int w2) {
+ int dx = x1 - x2;
+ int dy = y1 - y2;
+ int dz = z1 - z2;
+ int dw = w1 - w2;
+ return Math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
+ }
+
+ /**
+ * Return the squared distance between (x1, y1, z1, w1)
and (x2, y2, z2, w2)
.
+ *
+ * @param x1
+ * the x component of the first vector
+ * @param y1
+ * the y component of the first vector
+ * @param z1
+ * the z component of the first vector
+ * @param w1
+ * the w component of the first vector
+ * @param x2
+ * the x component of the second vector
+ * @param y2
+ * the y component of the second vector
+ * @param z2
+ * the z component of the second vector
+ * @param w2
+ * the w component of the second vector
+ * @return the euclidean distance squared
+ */
+ public static long distanceSquared(int x1, int y1, int z1, int w1, int x2, int y2, int z2, int w2) {
+ int dx = x1 - x2;
+ int dy = y1 - y2;
+ int dz = z1 - z2;
+ int dw = w1 - w2;
+ return dx * dx + dy * dy + dz * dz + dw * dw;
+ }
+
+ public int dot(Vector4ic v) {
+ return x * v.x() + y * v.y() + z * v.z() + w * v.w();
+ }
+
+ /**
+ * Set all components to zero.
+ *
+ * @return this
+ */
+ public Vector4i zero() {
+ x = 0;
+ y = 0;
+ z = 0;
+ w = 0;
+ return this;
+ }
+
+ /**
+ * Negate this vector.
+ *
+ * @return this
+ */
+ public Vector4i negate() {
+ this.x = -x;
+ this.y = -y;
+ this.z = -z;
+ this.w = -w;
+ return this;
+ }
+
+ public Vector4i negate(Vector4i dest) {
+ dest.x = -x;
+ dest.y = -y;
+ dest.z = -z;
+ dest.w = -w;
+ return dest;
+ }
+
+ /**
+ * Return a string representation of this vector.
+ *
+ * This method creates a new {@link DecimalFormat} on every invocation with the format string "0.000E0;-
".
+ *
+ * @return the string representation
+ */
+ public String toString() {
+ return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
+ }
+
+ /**
+ * Return a string representation of this vector by formatting the vector components with the given {@link NumberFormat}.
+ *
+ * @param formatter
+ * the {@link NumberFormat} used to format the vector components with
+ * @return the string representation
+ */
+ public String toString(NumberFormat formatter) {
+ return "(" + formatter.format(x) + " " + formatter.format(y) + " " + formatter.format(z) + " " + formatter.format(w) + ")";
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeInt(x);
+ out.writeInt(y);
+ out.writeInt(z);
+ out.writeInt(w);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ x = in.readInt();
+ y = in.readInt();
+ z = in.readInt();
+ w = in.readInt();
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4i min(Vector4ic v) {
+ this.x = x < v.x() ? x : v.x();
+ this.y = y < v.y() ? y : v.y();
+ this.z = z < v.z() ? z : v.z();
+ this.w = w < v.w() ? w : v.w();
+ return this;
+ }
+
+ public Vector4i min(Vector4ic v, Vector4i dest) {
+ dest.x = x < v.x() ? x : v.x();
+ dest.y = y < v.y() ? y : v.y();
+ dest.z = z < v.z() ? z : v.z();
+ dest.w = w < v.w() ? w : v.w();
+ return dest;
+ }
+
+ /**
+ * Set the components of this vector to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @return this
+ */
+ public Vector4i max(Vector4ic v) {
+ this.x = x > v.x() ? x : v.x();
+ this.y = y > v.y() ? y : v.y();
+ this.z = z > v.z() ? z : v.z();
+ this.w = w > v.w() ? w : v.w();
+ return this;
+ }
+
+ public Vector4i max(Vector4ic v, Vector4i dest) {
+ dest.x = x > v.x() ? x : v.x();
+ dest.y = y > v.y() ? y : v.y();
+ dest.z = z > v.z() ? z : v.z();
+ dest.w = w > v.w() ? w : v.w();
+ return dest;
+ }
+
+ /**
+ * Compute the absolute of each of this vector's components.
+ *
+ * @return this
+ */
+ public Vector4i absolute() {
+ this.x = Math.abs(x);
+ this.y = Math.abs(y);
+ this.z = Math.abs(z);
+ this.w = Math.abs(w);
+ return this;
+ }
+
+ public Vector4i absolute(Vector4i dest) {
+ dest.x = Math.abs(x);
+ dest.y = Math.abs(y);
+ dest.z = Math.abs(z);
+ dest.w = Math.abs(w);
+ return dest;
+ }
+
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + x;
+ result = prime * result + y;
+ result = prime * result + z;
+ result = prime * result + w;
+ return result;
+ }
+
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Vector4i other = (Vector4i) obj;
+ if (x != other.x) {
+ return false;
+ }
+ if (y != other.y) {
+ return false;
+ }
+ if (z != other.z) {
+ return false;
+ }
+ if (w != other.w) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean equals(int x, int y, int z, int w) {
+ if (this.x != x)
+ return false;
+ if (this.y != y)
+ return false;
+ if (this.z != z)
+ return false;
+ if (this.w != w)
+ return false;
+ return true;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4ic.java b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4ic.java
new file mode 100644
index 000000000..b4cd5a40b
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/Vector4ic.java
@@ -0,0 +1,432 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * Interface to a read-only view of a 4-dimensional vector of integers.
+ *
+ * @author Kai Burjack
+ */
+public interface Vector4ic {
+
+ /**
+ * @return the value of the x component
+ */
+ int x();
+
+ /**
+ * @return the value of the y component
+ */
+ int y();
+
+ /**
+ * @return the value of the z component
+ */
+ int z();
+
+ /**
+ * @return the value of the w component
+ */
+ int w();
+
+ /**
+ * Store this vector into the supplied {@link IntBuffer} at the current
+ * buffer {@link IntBuffer#position() position}.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * In order to specify the offset into the IntBuffer at which the vector is
+ * stored, use {@link #get(int, IntBuffer)}, taking the absolute position as
+ * parameter.
+ *
+ * @see #get(int, IntBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ IntBuffer get(IntBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link IntBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given IntBuffer.
+ *
+ * @param index
+ * the absolute position into the IntBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ IntBuffer get(int index, IntBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} at the current
+ * buffer {@link ByteBuffer#position() position}.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * In order to specify the offset into the ByteBuffer at which the vector is
+ * stored, use {@link #get(int, ByteBuffer)}, taking the absolute position
+ * as parameter.
+ *
+ * @see #get(int, ByteBuffer)
+ *
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(ByteBuffer buffer);
+
+ /**
+ * Store this vector into the supplied {@link ByteBuffer} starting at the
+ * specified absolute buffer position/index.
+ *
+ * This method will not increment the position of the given ByteBuffer.
+ *
+ * @param index
+ * the absolute position into the ByteBuffer
+ * @param buffer
+ * will receive the values of this vector in x, y, z, w
order
+ * @return the passed in buffer
+ */
+ ByteBuffer get(int index, ByteBuffer buffer);
+
+ /**
+ * Store this vector at the given off-heap memory address.
+ *
+ * This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
+ *
+ * This method is unsafe as it can result in a crash of the JVM process when the specified address range does not belong to this process.
+ *
+ * @param address
+ * the off-heap address where to store this vector
+ * @return this
+ */
+ Vector4ic getToAddress(long address);
+
+ /**
+ * Subtract the supplied vector from this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to subtract from this
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i sub(Vector4ic v, Vector4i dest);
+
+ /**
+ * Subtract (x, y, z, w)
from this and store the result in
+ * dest
.
+ *
+ * @param x
+ * the x component to subtract
+ * @param y
+ * the y component to subtract
+ * @param z
+ * the z component to subtract
+ * @param w
+ * the w component to subtract
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i sub(int x, int y, int z, int w, Vector4i dest);
+
+ /**
+ * Add the supplied vector to this one and store the result in
+ * dest
.
+ *
+ * @param v
+ * the vector to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i add(Vector4ic v, Vector4i dest);
+
+ /**
+ * Increment the components of this vector by the given values and store the
+ * result in dest
.
+ *
+ * @param x
+ * the x component to add
+ * @param y
+ * the y component to add
+ * @param z
+ * the z component to add
+ * @param w
+ * the w component to add
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i add(int x, int y, int z, int w, Vector4i dest);
+
+ /**
+ * Multiply this Vector4i component-wise by another Vector4ic and store the
+ * result in dest
.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i mul(Vector4ic v, Vector4i dest);
+
+ /**
+ * Divide this Vector4i component-wise by another Vector4ic and store the
+ * result in dest
.
+ *
+ * @param v
+ * the vector to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i div(Vector4ic v, Vector4i dest);
+
+ /**
+ * Multiply all components of this {@link Vector4i} by the given scalar
+ * value and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to multiply by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i mul(int scalar, Vector4i dest);
+
+ /**
+ * Divide all components of this {@link Vector4i} by the given scalar value
+ * and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i div(float scalar, Vector4i dest);
+
+ /**
+ * Divide all components of this {@link Vector4i} by the given scalar value
+ * and store the result in dest
.
+ *
+ * @param scalar
+ * the scalar to divide by
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i div(int scalar, Vector4i dest);
+
+ /**
+ * Return the length squared of this vector.
+ *
+ * @return the length squared
+ */
+ long lengthSquared();
+
+ /**
+ * Return the length of this vector.
+ *
+ * @return the length
+ */
+ double length();
+
+ /**
+ * Return the distance between this Vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the distance
+ */
+ double distance(Vector4ic v);
+
+ /**
+ * Return the distance between this
vector and (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the euclidean distance
+ */
+ double distance(int x, int y, int z, int w);
+
+ /**
+ * Return the grid distance in between (aka 1-Norm, Minkowski or Manhattan distance)
+ * (x, y)
.
+ *
+ * @param v
+ * the other vector
+ * @return the grid distance
+ */
+ long gridDistance(Vector4ic v);
+
+ /**
+ * Return the grid distance in between (aka 1-Norm, Minkowski or Manhattan distance)
+ * (x, y)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the grid distance
+ */
+ long gridDistance(int x, int y, int z, int w);
+
+ /**
+ * Return the square of the distance between this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the squared of the distance
+ */
+ int distanceSquared(Vector4ic v);
+
+ /**
+ * Return the square of the distance between this
vector and
+ * (x, y, z, w)
.
+ *
+ * @param x
+ * the x component of the other vector
+ * @param y
+ * the y component of the other vector
+ * @param z
+ * the z component of the other vector
+ * @param w
+ * the w component of the other vector
+ * @return the square of the distance
+ */
+ int distanceSquared(int x, int y, int z, int w);
+
+ /**
+ * Compute the dot product (inner product) of this vector and v
.
+ *
+ * @param v
+ * the other vector
+ * @return the dot product
+ */
+ int dot(Vector4ic v);
+
+ /**
+ * Negate this vector and store the result in dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i negate(Vector4i dest);
+
+ /**
+ * Set the components of dest
to be the component-wise minimum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i min(Vector4ic v, Vector4i dest);
+
+ /**
+ * Set the components of dest
to be the component-wise maximum of this and the other vector.
+ *
+ * @param v
+ * the other vector
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i max(Vector4ic v, Vector4i dest);
+
+ /**
+ * Get the value of the specified component of this vector.
+ *
+ * @param component
+ * the component, within [0..3]
+ * @return the value
+ * @throws IllegalArgumentException if component
is not within [0..3]
+ */
+ int get(int component) throws IllegalArgumentException;
+
+ /**
+ * Determine the component with the biggest absolute value.
+ *
+ * @return the component index, within [0..3]
+ */
+ int maxComponent();
+
+ /**
+ * Determine the component with the smallest (towards zero) absolute value.
+ *
+ * @return the component index, within [0..3]
+ */
+ int minComponent();
+
+ /**
+ * Compute the absolute of each of this vector's components
+ * and store the result into dest
.
+ *
+ * @param dest
+ * will hold the result
+ * @return dest
+ */
+ Vector4i absolute(Vector4i dest);
+
+ /**
+ * Compare the vector components of this
vector with the given (x, y, z, w)
+ * and return whether all of them are equal.
+ *
+ * @param x
+ * the x component to compare to
+ * @param y
+ * the y component to compare to
+ * @param z
+ * the z component to compare to
+ * @param w
+ * the w component to compare to
+ * @return true
if all the vector components are equal
+ */
+ boolean equals(int x, int y, int z, int w);
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/package.html b/src/main/java/com/jozufozu/flywheel/repack/joml/package.html
new file mode 100644
index 000000000..02a84240d
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/package.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+Contains all classes of JOML.
+If you like to know more about JOML, please visit:
+
+
+
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/BestCandidateSampling.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/BestCandidateSampling.java
new file mode 100644
index 000000000..07a0eb925
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/BestCandidateSampling.java
@@ -0,0 +1,1034 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+
+import com.jozufozu.flywheel.repack.joml.Random;
+import com.jozufozu.flywheel.repack.joml.Vector2f;
+import com.jozufozu.flywheel.repack.joml.Vector3f;
+
+/**
+ * Creates samples using the "Best Candidate" algorithm.
+ *
+ * @author Kai Burjack
+ */
+public class BestCandidateSampling {
+
+ private static final class IntHolder {
+ int value;
+ }
+
+ /**
+ * Generates Best Candidate samples on a unit sphere.
+ *
+ * References:
+ *
+ *
+ * @author Kai Burjack
+ */
+ public static class Sphere {
+ /**
+ * Implementation of a Hierarchical Triangular Mesh structure to index the sample points on the unit sphere for accelerating 1-nearest neighbor searches.
+ *
+ * @author Kai Burjack
+ */
+ private static final class Node {
+ private static final int MAX_OBJECTS_PER_NODE = 32;
+
+ private float v0x, v0y, v0z;
+ private float v1x, v1y, v1z;
+ private float v2x, v2y, v2z;
+ private float cx, cy, cz;
+ private float arc;
+
+ private ArrayList objects;
+ private Node[] children;
+
+ Node() {
+ this.children = new Node[8];
+ float s = 1f;
+ this.arc = 2.0f * (float) Math.PI;
+ /*
+ * See: https://arxiv.org/ftp/cs/papers/0701/0701164.pdf
+ */
+ this.children[0] = new Node(-s, 0, 0, 0, 0, s, 0, s, 0);
+ this.children[1] = new Node(0, 0, s, s, 0, 0, 0, s, 0);
+ this.children[2] = new Node(s, 0, 0, 0, 0, -s, 0, s, 0);
+ this.children[3] = new Node(0, 0, -s, -s, 0, 0, 0, s, 0);
+ this.children[4] = new Node(-s, 0, 0, 0, -s, 0, 0, 0, s);
+ this.children[5] = new Node(0, 0, s, 0, -s, 0, s, 0, 0);
+ this.children[6] = new Node(s, 0, 0, 0, -s, 0, 0, 0, -s);
+ this.children[7] = new Node(0, 0, -s, 0, -s, 0, -s, 0, 0);
+ }
+
+ private Node(float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2) {
+ this.v0x = x0;
+ this.v0y = y0;
+ this.v0z = z0;
+ this.v1x = x1;
+ this.v1y = y1;
+ this.v1z = z1;
+ this.v2x = x2;
+ this.v2y = y2;
+ this.v2z = z2;
+ cx = (v0x + v1x + v2x) / 3.0f;
+ cy = (v0y + v1y + v2y) / 3.0f;
+ cz = (v0z + v1z + v2z) / 3.0f;
+ float invCLen = Math.invsqrt(cx * cx + cy * cy + cz * cz);
+ cx *= invCLen;
+ cy *= invCLen;
+ cz *= invCLen;
+ // Compute maximum radius around triangle centroid
+ float arc1 = greatCircleDist(cx, cy, cz, v0x, v0y, v0z);
+ float arc2 = greatCircleDist(cx, cy, cz, v1x, v1y, v1z);
+ float arc3 = greatCircleDist(cx, cy, cz, v2x, v2y, v2z);
+ float dist = Math.max(Math.max(arc1, arc2), arc3);
+ /*
+ * Convert radius into diameter, but also take into account the linear
+ * arccos approximation we use.
+ * This value was obtained empirically!
+ */
+ dist *= 1.7f;
+ this.arc = dist;
+ }
+
+ private void split() {
+ float w0x = v1x + v2x;
+ float w0y = v1y + v2y;
+ float w0z = v1z + v2z;
+ float len0 = Math.invsqrt(w0x * w0x + w0y * w0y + w0z * w0z);
+ w0x *= len0;
+ w0y *= len0;
+ w0z *= len0;
+ float w1x = v0x + v2x;
+ float w1y = v0y + v2y;
+ float w1z = v0z + v2z;
+ float len1 = Math.invsqrt(w1x * w1x + w1y * w1y + w1z * w1z);
+ w1x *= len1;
+ w1y *= len1;
+ w1z *= len1;
+ float w2x = v0x + v1x;
+ float w2y = v0y + v1y;
+ float w2z = v0z + v1z;
+ float len2 = Math.invsqrt(w2x * w2x + w2y * w2y + w2z * w2z);
+ w2x *= len2;
+ w2y *= len2;
+ w2z *= len2;
+ children = new Node[4];
+ /*
+ * See: https://arxiv.org/ftp/cs/papers/0701/0701164.pdf
+ */
+ children[0] = new Node(v0x, v0y, v0z, w2x, w2y, w2z, w1x, w1y, w1z);
+ children[1] = new Node(v1x, v1y, v1z, w0x, w0y, w0z, w2x, w2y, w2z);
+ children[2] = new Node(v2x, v2y, v2z, w1x, w1y, w1z, w0x, w0y, w0z);
+ children[3] = new Node(w0x, w0y, w0z, w1x, w1y, w1z, w2x, w2y, w2z);
+ }
+
+ private void insertIntoChild(Vector3f o) {
+ for (int i = 0; i < children.length; i++) {
+ Node c = children[i];
+ /*
+ * Idea: Test whether ray from origin towards point cuts triangle
+ *
+ * See: http://math.stackexchange.com/questions/1244512/point-in-a-spherical-triangle-test
+ */
+ if (isPointOnSphericalTriangle(o.x, o.y, o.z, c.v0x, c.v0y, c.v0z, c.v1x, c.v1y, c.v1z, c.v2x, c.v2y, c.v2z, 1E-6f)) {
+ c.insert(o);
+ return;
+ }
+ }
+ }
+
+ void insert(Vector3f object) {
+ if (children != null) {
+ insertIntoChild(object);
+ return;
+ }
+ if (objects != null && objects.size() == MAX_OBJECTS_PER_NODE) {
+ split();
+ for (int i = 0; i < MAX_OBJECTS_PER_NODE; i++)
+ insertIntoChild((Vector3f) objects.get(i));
+ objects = null;
+ insertIntoChild(object);
+ } else {
+ if (objects == null)
+ objects = new ArrayList(MAX_OBJECTS_PER_NODE);
+ objects.add(object);
+ }
+ }
+
+ /**
+ * This is essentially a ray cast from the origin of the sphere to the point to test and then checking whether that ray goes through the triangle.
+ *
+ * Reference: Fast,
+ * Minimum Storage Ray/Triangle Intersection
+ */
+ private static boolean isPointOnSphericalTriangle(float x, float y, float z, float v0X, float v0Y, float v0Z, float v1X, float v1Y, float v1Z, float v2X, float v2Y,
+ float v2Z, float epsilon) {
+ float edge1X = v1X - v0X;
+ float edge1Y = v1Y - v0Y;
+ float edge1Z = v1Z - v0Z;
+ float edge2X = v2X - v0X;
+ float edge2Y = v2Y - v0Y;
+ float edge2Z = v2Z - v0Z;
+ float pvecX = y * edge2Z - z * edge2Y;
+ float pvecY = z * edge2X - x * edge2Z;
+ float pvecZ = x * edge2Y - y * edge2X;
+ float det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ;
+ if (det > -epsilon && det < epsilon)
+ return false;
+ float tvecX = -v0X;
+ float tvecY = -v0Y;
+ float tvecZ = -v0Z;
+ float invDet = 1.0f / det;
+ float u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet;
+ if (u < 0.0f || u > 1.0f)
+ return false;
+ float qvecX = tvecY * edge1Z - tvecZ * edge1Y;
+ float qvecY = tvecZ * edge1X - tvecX * edge1Z;
+ float qvecZ = tvecX * edge1Y - tvecY * edge1X;
+ float v = (x * qvecX + y * qvecY + z * qvecZ) * invDet;
+ if (v < 0.0f || u + v > 1.0f)
+ return false;
+ float t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet;
+ return t >= epsilon;
+ }
+
+ private int child(float x, float y, float z) {
+ for (int i = 0; i < children.length; i++) {
+ Node c = children[i];
+ if (isPointOnSphericalTriangle(x, y, z, c.v0x, c.v0y, c.v0z, c.v1x, c.v1y, c.v1z, c.v2x, c.v2y, c.v2z, 1E-5f))
+ return i;
+ }
+ // No child found. This can happen in 'nearest()' when querying possible nearby nodes
+ return 0;
+ }
+
+ /**
+ * Reference: https://en.wikipedia.org/
+ */
+ private float greatCircleDist(float x1, float y1, float z1, float x2, float y2, float z2) {
+ float dot = x1 * x2 + y1 * y2 + z1 * z2;
+ /*
+ * Just use a linear function, because we (mostly) do less-than comparisons on the result.
+ * We just need a linear function which:
+ * f(-1) = PI
+ * f(0) = PI/2
+ * f(1) = 0
+ */
+ return (float) (-Math.PIHalf * dot + Math.PIHalf);
+ //return (float) Math.acos(dot);
+ }
+
+ float nearest(float x, float y, float z) {
+ return nearest(x, y, z, Float.POSITIVE_INFINITY);
+ }
+ float nearest(float x, float y, float z, float n) {
+ float gcd = greatCircleDist(x, y, z, cx, cy, cz);
+ /*
+ * If great-circle-distance between query point and centroid is larger than the current smallest distance 'n' plus the great circle diameter 'arc', we abort here,
+ * because then it is not possible for any point in the triangle patch to be closer to the query point than 'n'.
+ */
+ /*
+ * Yes, we are subtracting two great-circle distances from one another here, which we did not even compute correctly
+ * using our overly linear arccos approximation. But the 1.7 factor above will take care that we still stay conservative
+ * enough here and not rejecting triangle patches which would contain samples nearer than 'n'.
+ */
+ if (gcd - arc > n)
+ return n;
+ float nr = n;
+ if (children != null) {
+ int num = children.length, mod = num-1;
+ for (int i = child(x, y, z), c = 0; c < num; i = (i + 1) & mod, c++) {
+ float n1 = children[i].nearest(x, y, z, nr);
+ nr = Math.min(n1, nr);
+ }
+ return nr;
+ }
+ for (int i = 0; objects != null && i < objects.size(); i++) {
+ Vector3f o = (Vector3f) objects.get(i);
+ float d = greatCircleDist(o.x, o.y, o.z, x, y, z);
+ if (d < nr)
+ nr = d;
+ }
+ return nr;
+ }
+ }
+
+ private boolean onHemisphere;
+ private int numSamples;
+ private int numCandidates = 60; // <- use a reasonable default
+ private long seed;
+
+ /**
+ * Create a new instance of {@link Sphere} to configure and generate 'best candidate' sample positions on the unit sphere.
+ */
+ public Sphere() {}
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xyzs
float array.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xyzs
+ * will hold the x, y and z coordinates of all samples in the order XYZXYZXYZ...
.
+ * This array must have a length of at least numSamples
+ * @return this
+ */
+ public Sphere generate(final float[] xyzs) {
+ final IntHolder i = new IntHolder();
+ return generate(new Callback3d() {
+ public void onNewSample(float x, float y, float z) {
+ xyzs[3 * i.value + 0] = x;
+ xyzs[3 * i.value + 1] = y;
+ xyzs[3 * i.value + 2] = z;
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xyzs
FloatBuffer.
+ *
+ * The samples will be written starting at the current position of the FloatBuffer. The position of the FloatBuffer will not be modified.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xyzs
+ * will hold the x, y and z coordinates of all samples in the order XYZXYZXYZ...
.
+ * This FloatBuffer must have at least numSamples
remaining elements.
+ * The position of the buffer will not be modified by this method
+ * @return this
+ */
+ public Sphere generate(final FloatBuffer xyzs) {
+ final IntHolder i = new IntHolder();
+ final int pos = xyzs.position();
+ return generate(new Callback3d() {
+ public void onNewSample(float x, float y, float z) {
+ xyzs.put(pos + 3 * i.value + 0, x);
+ xyzs.put(pos + 3 * i.value + 1, y);
+ xyzs.put(pos + 3 * i.value + 2, z);
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Set the seed to initialize the pseudo-random number generator with.
+ *
+ * @param seed
+ * the seed value
+ * @return this
+ */
+ public Sphere seed(long seed) {
+ this.seed = seed;
+ return this;
+ }
+
+ /**
+ * Set the number of samples to generate.
+ *
+ * @param numSamples
+ * the number of samples
+ * @return this
+ */
+ public Sphere numSamples(int numSamples) {
+ this.numSamples = numSamples;
+ return this;
+ }
+
+ /**
+ * Set the number of candidates to try for each generated sample.
+ *
+ * @param numCandidates
+ * the number of candidates to try
+ * @return this
+ */
+ public Sphere numCandidates(int numCandidates) {
+ this.numCandidates = numCandidates;
+ return this;
+ }
+
+ /**
+ * Set whether to generate samples on a hemisphere around the +Z
axis.
+ *
+ * The default is false
, which will generate samples on the whole unit sphere.
+ *
+ * @param onHemisphere
+ * whether to generate samples on the hemisphere
+ * @return this
+ */
+ public Sphere onHemisphere(boolean onHemisphere) {
+ this.onHemisphere = onHemisphere;
+ return this;
+ }
+
+ /**
+ * Generate 'best candidate' sample call the given callback
for each generated sample.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param callback
+ * will be called with the coordinates of each generated sample position
+ * @return this
+ */
+ public Sphere generate(Callback3d callback) {
+ Random rnd = new Random(seed);
+ Node otree = new Node();
+ for (int i = 0; i < numSamples; i++) {
+ float bestX = Float.NaN, bestY = Float.NaN, bestZ = Float.NaN, bestDist = 0.0f;
+ for (int c = 0; c < numCandidates; c++) {
+ /*
+ * Random point on sphere
+ *
+ * Reference: http://mathworld.wolfram.com/
+ */
+ float x1, x2;
+ do {
+ x1 = rnd.nextFloat() * 2.0f - 1.0f;
+ x2 = rnd.nextFloat() * 2.0f - 1.0f;
+ } while (x1 * x1 + x2 * x2 > 1.0f);
+ float sqrt = (float) Math.sqrt(1.0 - x1 * x1 - x2 * x2);
+ float x = 2 * x1 * sqrt;
+ float y = 2 * x2 * sqrt;
+ float z = 1.0f - 2.0f * (x1 * x1 + x2 * x2);
+ if (onHemisphere) {
+ z = Math.abs(z);
+ }
+ float minDist = otree.nearest(x, y, z);
+ if (minDist > bestDist) {
+ bestDist = minDist;
+ bestX = x;
+ bestY = y;
+ bestZ = z;
+ }
+ }
+ callback.onNewSample(bestX, bestY, bestZ);
+ otree.insert(new Vector3f(bestX, bestY, bestZ));
+ }
+ return this;
+ }
+ }
+
+ /**
+ * Simple quatree that can handle points and 1-nearest neighbor search.
+ *
+ * @author Kai Burjack
+ */
+ private static class QuadTree {
+ private static final int MAX_OBJECTS_PER_NODE = 32;
+
+ // Constants for the quadrants of the quadtree
+ private static final int PXNY = 0;
+ private static final int NXNY = 1;
+ private static final int NXPY = 2;
+ private static final int PXPY = 3;
+
+ private float minX, minY, hs;
+ private ArrayList objects;
+ private QuadTree[] children;
+
+ QuadTree(float minX, float minY, float size) {
+ this.minX = minX;
+ this.minY = minY;
+ this.hs = size * 0.5f;
+ }
+
+ private void split() {
+ children = new QuadTree[4];
+ children[NXNY] = new QuadTree(minX, minY, hs);
+ children[PXNY] = new QuadTree(minX + hs, minY, hs);
+ children[NXPY] = new QuadTree(minX, minY + hs, hs);
+ children[PXPY] = new QuadTree(minX + hs, minY + hs, hs);
+ }
+
+ private void insertIntoChild(Vector2f o) {
+ children[quadrant(o.x, o.y)].insert(o);
+ }
+
+ void insert(Vector2f object) {
+ if (children != null) {
+ insertIntoChild(object);
+ return;
+ }
+ if (objects != null && objects.size() == MAX_OBJECTS_PER_NODE) {
+ split();
+ for (int i = 0; i < objects.size(); i++)
+ insertIntoChild((Vector2f) objects.get(i));
+ objects = null;
+ insertIntoChild(object);
+ } else {
+ if (objects == null)
+ objects = new ArrayList(MAX_OBJECTS_PER_NODE);
+ objects.add(object);
+ }
+ }
+
+ private int quadrant(float x, float y) {
+ if (x < minX + hs) {
+ if (y < minY + hs)
+ return NXNY;
+ return NXPY;
+ }
+ if (y < minY + hs)
+ return PXNY;
+ return PXPY;
+ }
+
+ float nearest(float x, float y, float lowerBound, float upperBound) {
+ float ub = upperBound;
+ if (x < minX - upperBound || x > minX + hs * 2 + upperBound || y < minY - upperBound
+ || y > minY + hs * 2 + upperBound)
+ return ub;
+ if (children != null) {
+ for (int i = quadrant(x, y), c = 0; c < 4; i = (i + 1) & 3, c++) {
+ float n1 = children[i].nearest(x, y, lowerBound, ub);
+ ub = Math.min(n1, ub);
+ if (ub <= lowerBound)
+ return lowerBound;
+ }
+ return ub;
+ }
+ float ub2 = ub * ub;
+ float lb2 = lowerBound * lowerBound;
+ for (int i = 0; objects != null && i < objects.size(); i++) {
+ Vector2f o = (Vector2f) objects.get(i);
+ float d = o.distanceSquared(x, y);
+ if (d <= lb2)
+ return lowerBound;
+ if (d < ub2)
+ ub2 = d;
+ }
+ return (float) Math.sqrt(ub2);
+ }
+ }
+
+ /**
+ * Generates Best Candidate samples on a unit disk.
+ *
+ * @author Kai Burjack
+ */
+ public static class Disk {
+ private int numSamples;
+ private int numCandidates = 60; // <- use a reasonable default
+ private long seed;
+
+ /**
+ * Create a new instance of {@link Disk} to configure and generate 'best candidate' sample positions on the unit disk.
+ */
+ public Disk() {}
+
+ /**
+ * Set the seed to initialize the pseudo-random number generator with.
+ *
+ * @param seed
+ * the seed value
+ * @return this
+ */
+ public Disk seed(long seed) {
+ this.seed = seed;
+ return this;
+ }
+
+ /**
+ * Set the number of samples to generate.
+ *
+ * @param numSamples
+ * the number of samples
+ * @return this
+ */
+ public Disk numSamples(int numSamples) {
+ this.numSamples = numSamples;
+ return this;
+ }
+
+ /**
+ * Set the number of candidates to try for each generated sample.
+ *
+ * @param numCandidates
+ * the number of candidates to try
+ * @return this
+ */
+ public Disk numCandidates(int numCandidates) {
+ this.numCandidates = numCandidates;
+ return this;
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xys
float array.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xys
+ * will hold the x and y coordinates of all samples in the order XYXYXY...
.
+ * This array must have a length of at least numSamples
+ * @return this
+ */
+ public Disk generate(final float[] xys) {
+ final IntHolder i = new IntHolder();
+ return generate(new Callback2d() {
+ public void onNewSample(float x, float y) {
+ xys[2 * i.value + 0] = x;
+ xys[2 * i.value + 1] = y;
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xys
FloatBuffer.
+ *
+ * The samples will be written starting at the current position of the FloatBuffer. The position of the FloatBuffer will not be modified.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xys
+ * will hold the x and y coordinates of all samples in the order XYXYXY...
. This FloatBuffer must have at least numSamples
remaining elements. The
+ * position of the buffer will not be modified by this method
+ * @return this
+ */
+ public Disk generate(final FloatBuffer xys) {
+ final IntHolder i = new IntHolder();
+ final int pos = xys.position();
+ return generate(new Callback2d() {
+ public void onNewSample(float x, float y) {
+ xys.put(pos + 3 * i.value + 0, x);
+ xys.put(pos + 3 * i.value + 1, y);
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and call the given callback
for each generated sample.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param callback
+ * will be called with the coordinates of each generated sample position
+ * @return this
+ */
+ public Disk generate(Callback2d callback) {
+ QuadTree qtree = new QuadTree(-1, -1, 2);
+ Random rnd = new Random(seed);
+ for (int i = 0; i < numSamples; i++) {
+ float bestX = 0, bestY = 0, bestDist = 0.0f;
+ for (int c = 0; c < numCandidates; c++) {
+ float x, y;
+ do {
+ x = rnd.nextFloat() * 2.0f - 1.0f;
+ y = rnd.nextFloat() * 2.0f - 1.0f;
+ } while (x * x + y * y > 1.0f);
+ float minDist = qtree.nearest(x, y, bestDist, Float.POSITIVE_INFINITY);
+ if (minDist > bestDist) {
+ bestDist = minDist;
+ bestX = x;
+ bestY = y;
+ }
+ }
+ callback.onNewSample(bestX, bestY);
+ qtree.insert(new Vector2f(bestX, bestY));
+ }
+ return this;
+ }
+ }
+
+ /**
+ * Generates Best Candidate samples on a unit quad.
+ *
+ * @author Kai Burjack
+ */
+ public static class Quad {
+ private int numSamples;
+ private int numCandidates = 60; // <- use a reasonable default
+ private long seed;
+
+ /**
+ * Create a new instance of {@link Quad} to configure and generate 'best candidate' sample positions on the unit quad.
+ */
+ public Quad() {}
+
+ /**
+ * Set the seed to initialize the pseudo-random number generator with.
+ *
+ * @param seed
+ * the seed value
+ * @return this
+ */
+ public Quad seed(long seed) {
+ this.seed = seed;
+ return this;
+ }
+
+ /**
+ * Set the number of samples to generate.
+ *
+ * @param numSamples
+ * the number of samples
+ * @return this
+ */
+ public Quad numSamples(int numSamples) {
+ this.numSamples = numSamples;
+ return this;
+ }
+
+ /**
+ * Set the number of candidates to try for each generated sample.
+ *
+ * @param numCandidates
+ * the number of candidates to try
+ * @return this
+ */
+ public Quad numCandidates(int numCandidates) {
+ this.numCandidates = numCandidates;
+ return this;
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xyzs
float array.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xyzs
+ * will hold the x, y and z coordinates of all samples in the order XYZXYZXYZ...
.
+ * This array must have a length of at least numSamples
+ * @return this
+ */
+ public Quad generate(final float[] xyzs) {
+ final IntHolder i = new IntHolder();
+ return generate(new Callback2d() {
+ public void onNewSample(float x, float y) {
+ xyzs[2 * i.value + 0] = x;
+ xyzs[2 * i.value + 1] = y;
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xys
FloatBuffer.
+ *
+ * The samples will be written starting at the current position of the FloatBuffer. The position of the FloatBuffer will not be modified.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xys
+ * will hold the x and y coordinates of all samples in the order XYXYXY...
. This FloatBuffer must have at least numSamples
remaining elements. The position of
+ * the buffer will not be modified by this method
+ * @return this
+ */
+ public Quad generate(final FloatBuffer xys) {
+ final IntHolder i = new IntHolder();
+ final int pos = xys.position();
+ return generate(new Callback2d() {
+ public void onNewSample(float x, float y) {
+ xys.put(pos + 3 * i.value + 0, x);
+ xys.put(pos + 3 * i.value + 1, y);
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and call the given callback
for each generated sample.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param callback
+ * will be called with the coordinates of each generated sample position
+ * @return this
+ */
+ public Quad generate(Callback2d callback) {
+ QuadTree qtree = new QuadTree(-1, -1, 2);
+ Random rnd = new Random(seed);
+ for (int i = 0; i < numSamples; i++) {
+ float bestX = 0, bestY = 0, bestDist = 0.0f;
+ for (int c = 0; c < numCandidates; c++) {
+ float x = rnd.nextFloat() * 2.0f - 1.0f;
+ float y = rnd.nextFloat() * 2.0f - 1.0f;
+ float minDist = qtree.nearest(x, y, bestDist, Float.POSITIVE_INFINITY);
+ if (minDist > bestDist) {
+ bestDist = minDist;
+ bestX = x;
+ bestY = y;
+ }
+ }
+ callback.onNewSample(bestX, bestY);
+ qtree.insert(new Vector2f(bestX, bestY));
+ }
+ return this;
+ }
+ }
+
+ /**
+ * Simple octree for points and 1-nearest neighbor distance query.
+ *
+ * @author Kai Burjack
+ */
+ private static class Octree {
+ private static final int MAX_OBJECTS_PER_NODE = 32;
+
+ // Constants for the octants of the octree
+ private static final int PXNYNZ = 0;
+ private static final int NXNYNZ = 1;
+ private static final int NXPYNZ = 2;
+ private static final int PXPYNZ = 3;
+ private static final int PXNYPZ = 4;
+ private static final int NXNYPZ = 5;
+ private static final int NXPYPZ = 6;
+ private static final int PXPYPZ = 7;
+
+ private float minX, minY, minZ, hs;
+ private ArrayList objects;
+ private Octree[] children;
+
+ Octree(float minX, float minY, float minZ, float size) {
+ this.minX = minX;
+ this.minY = minY;
+ this.minZ = minZ;
+ this.hs = size * 0.5f;
+ }
+
+ private void split() {
+ children = new Octree[8];
+ children[NXNYNZ] = new Octree(minX, minY, minZ, hs);
+ children[PXNYNZ] = new Octree(minX + hs, minY, minZ, hs);
+ children[NXPYNZ] = new Octree(minX, minY + hs, minZ, hs);
+ children[PXPYNZ] = new Octree(minX + hs, minY + hs, minZ, hs);
+ children[NXNYPZ] = new Octree(minX, minY, minZ + hs, hs);
+ children[PXNYPZ] = new Octree(minX + hs, minY, minZ + hs, hs);
+ children[NXPYPZ] = new Octree(minX, minY + hs, minZ + hs, hs);
+ children[PXPYPZ] = new Octree(minX + hs, minY + hs, minZ + hs, hs);
+ }
+
+ private void insertIntoChild(Vector3f o) {
+ children[octant(o.x, o.y, o.z)].insert(o);
+ }
+
+ void insert(Vector3f object) {
+ if (children != null) {
+ insertIntoChild(object);
+ return;
+ }
+ if (objects != null && objects.size() == MAX_OBJECTS_PER_NODE) {
+ split();
+ for (int i = 0; i < objects.size(); i++)
+ insertIntoChild((Vector3f) objects.get(i));
+ objects = null;
+ insertIntoChild(object);
+ } else {
+ if (objects == null)
+ objects = new ArrayList(MAX_OBJECTS_PER_NODE);
+ objects.add(object);
+ }
+ }
+
+ private int octant(float x, float y, float z) {
+ if (x < minX + hs)
+ if (y < minY + hs) {
+ if (z < minZ + hs)
+ return NXNYNZ;
+ return NXNYPZ;
+ } else if (z < minZ + hs)
+ return NXPYNZ;
+ else
+ return NXPYPZ;
+ else if (y < minY + hs) {
+ if (z < minZ + hs)
+ return PXNYNZ;
+ return PXNYPZ;
+ } else if (z < minZ + hs)
+ return PXPYNZ;
+ else
+ return PXPYPZ;
+ }
+
+ float nearest(float x, float y, float z, float lowerBound, float upperBound) {
+ float up = upperBound;
+ if (x < minX - upperBound || x > minX + hs * 2 + upperBound || y < minY - upperBound || y > minY + hs * 2 + upperBound ||
+ z < minZ - upperBound || z > minZ + hs * 2 + upperBound)
+ return up;
+ if (children != null) {
+ for (int i = octant(x, y, z), c = 0; c < 8; i = (i + 1) & 7, c++) {
+ float n1 = children[i].nearest(x, y, z, lowerBound, up);
+ up = Math.min(n1, up);
+ if (up <= lowerBound)
+ return lowerBound;
+ }
+ return up;
+ }
+ float up2 = up * up;
+ float lb2 = lowerBound * lowerBound;
+ for (int i = 0; objects != null && i < objects.size(); i++) {
+ Vector3f o = (Vector3f) objects.get(i);
+ float d = o.distanceSquared(x, y, z);
+ if (d <= lb2)
+ return lowerBound;
+ if (d < up2)
+ up2 = d;
+ }
+ return (float) Math.sqrt(up2);
+ }
+ }
+
+ /**
+ * Generates Best Candidate samples inside a unit cube.
+ *
+ * @author Kai Burjack
+ */
+ public static class Cube {
+ private int numSamples;
+ private int numCandidates = 60; // <- use a reasonable default
+ private long seed;
+
+ /**
+ * Create a new instance of {@link Cube} to configure and generate 'best candidate' sample positions
+ * on the unit cube with each sample tried numCandidates
number of times, and call the
+ * given callback
for each sample generate.
+ */
+ public Cube() {}
+
+ /**
+ * Set the seed to initialize the pseudo-random number generator with.
+ *
+ * @param seed
+ * the seed value
+ * @return this
+ */
+ public Cube seed(long seed) {
+ this.seed = seed;
+ return this;
+ }
+
+ /**
+ * Set the number of samples to generate.
+ *
+ * @param numSamples
+ * the number of samples
+ * @return this
+ */
+ public Cube numSamples(int numSamples) {
+ this.numSamples = numSamples;
+ return this;
+ }
+
+ /**
+ * Set the number of candidates to try for each generated sample.
+ *
+ * @param numCandidates
+ * the number of candidates to try
+ * @return this
+ */
+ public Cube numCandidates(int numCandidates) {
+ this.numCandidates = numCandidates;
+ return this;
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xyzs
float array.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xyzs
+ * will hold the x, y and z coordinates of all samples in the order XYZXYZXYZ...
.
+ * This array must have a length of at least numSamples
+ * @return this
+ */
+ public Cube generate(final float[] xyzs) {
+ final IntHolder i = new IntHolder();
+ return generate(new Callback3d() {
+ public void onNewSample(float x, float y, float z) {
+ xyzs[3 * i.value + 0] = x;
+ xyzs[3 * i.value + 1] = y;
+ xyzs[3 * i.value + 2] = z;
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and store the coordinates of all generated samples into the given xyzs
FloatBuffer.
+ *
+ * The samples will be written starting at the current position of the FloatBuffer. The position of the FloatBuffer will not be modified.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param xyzs
+ * will hold the x, y and z coordinates of all samples in the order XYZXYZXYZ...
.
+ * This FloatBuffer must have at least numSamples
remaining elements.
+ * The position of the buffer will not be modified by this method
+ * @return this
+ */
+ public Cube generate(final FloatBuffer xyzs) {
+ final IntHolder i = new IntHolder();
+ final int pos = xyzs.position();
+ return generate(new Callback3d() {
+ public void onNewSample(float x, float y, float z) {
+ xyzs.put(pos + 3 * i.value + 0, x);
+ xyzs.put(pos + 3 * i.value + 1, y);
+ xyzs.put(pos + 3 * i.value + 2, z);
+ i.value++;
+ }
+ });
+ }
+
+ /**
+ * Generate 'best candidate' sample positions and call the given callback
for each generated sample.
+ *
+ * This method performs heap allocations, so should be used sparingly.
+ *
+ * @param callback
+ * will be called with the coordinates of each generated sample position
+ * @return this
+ */
+ public Cube generate(Callback3d callback) {
+ Octree octree = new Octree(-1, -1, -1, 2);
+ Random rnd = new Random(seed);
+ for (int i = 0; i < numSamples; i++) {
+ float bestX = 0, bestY = 0, bestZ = 0, bestDist = 0.0f;
+ for (int c = 0; c < numCandidates; c++) {
+ float x = rnd.nextFloat() * 2.0f - 1.0f;
+ float y = rnd.nextFloat() * 2.0f - 1.0f;
+ float z = rnd.nextFloat() * 2.0f - 1.0f;
+ float minDist = octree.nearest(x, y, z, bestDist, Float.POSITIVE_INFINITY);
+ if (minDist > bestDist) {
+ bestDist = minDist;
+ bestX = x;
+ bestY = y;
+ bestZ = z;
+ }
+ }
+ callback.onNewSample(bestX, bestY, bestZ);
+ octree.insert(new Vector3f(bestX, bestY, bestZ));
+ }
+ return this;
+ }
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Callback2d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Callback2d.java
new file mode 100644
index 000000000..98380ed67
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Callback2d.java
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+/**
+ * Callback used for notifying about a new generated 2D sample.
+ *
+ * @author Kai Burjack
+ */
+public interface Callback2d {
+ /**
+ * Will be called whenever a new sample with the given coordinates (x, y)
is generated.
+ *
+ * @param x
+ * the x coordinate of the new sample point
+ * @param y
+ * the y coordinate of the new sample point
+ */
+ void onNewSample(float x, float y);
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Callback3d.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Callback3d.java
new file mode 100644
index 000000000..a9ff2c306
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Callback3d.java
@@ -0,0 +1,43 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+/**
+ * Callback used for notifying about a new generated 3D sample.
+ *
+ * @author Kai Burjack
+ */
+public interface Callback3d {
+ /**
+ * Will be called whenever a new sample with the given coordinates (x, y, z)
is generated.
+ *
+ * @param x
+ * the x coordinate of the new sample point
+ * @param y
+ * the y coordinate of the new sample point
+ * @param z
+ * the z coordinate of the new sample point
+ */
+ void onNewSample(float x, float y, float z);
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Convolution.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Convolution.java
new file mode 100644
index 000000000..2410129e7
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Convolution.java
@@ -0,0 +1,116 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+import java.nio.FloatBuffer;
+
+import com.jozufozu.flywheel.repack.joml.Math;
+
+/**
+ * Generates various convolution kernels.
+ *
+ * @author Kai Burjack
+ */
+public class Convolution {
+
+ /**
+ * Generate a Gaussian convolution kernel with the given number of rows and columns, and store
+ * the factors in row-major order in dest
.
+ *
+ * @param rows
+ * the number of rows (must be an odd number)
+ * @param cols
+ * the number of columns (must be an odd number)
+ * @param sigma
+ * the standard deviation of the filter kernel values
+ * @param dest
+ * will hold the kernel factors in row-major order
+ */
+ public static void gaussianKernel(int rows, int cols, float sigma, FloatBuffer dest) {
+ if ((rows & 1) == 0) {
+ throw new IllegalArgumentException("rows must be an odd number");
+ }
+ if ((cols & 1) == 0) {
+ throw new IllegalArgumentException("cols must be an odd number");
+ }
+ if (dest == null) {
+ throw new IllegalArgumentException("dest must not be null");
+ }
+ if (dest.remaining() < rows * cols) {
+ throw new IllegalArgumentException("dest must have at least " + (rows * cols) + " remaining values");
+ }
+ float sum = 0.0f;
+ int pos = dest.position();
+ for (int i = 0, y = -(rows - 1) / 2; y <= (rows - 1) / 2; y++) {
+ for (int x = -(cols - 1) / 2; x <= (cols - 1) / 2; x++, i++) {
+ float k = (float) Math.exp(-(y * y + x * x) / (2.0 * sigma * sigma));
+ dest.put(pos + i, k);
+ sum += k;
+ }
+ }
+ for (int i = 0; i < rows * cols; i++) {
+ dest.put(pos + i, dest.get(pos + i) / sum);
+ }
+ }
+
+ /**
+ * Generate a Gaussian convolution kernel with the given number of rows and columns, and store
+ * the factors in row-major order in dest
.
+ *
+ * @param rows
+ * the number of rows (must be an odd number)
+ * @param cols
+ * the number of columns (must be an odd number)
+ * @param sigma
+ * the standard deviation of the filter kernel values
+ * @param dest
+ * will hold the kernel factors in row-major order
+ */
+ public static void gaussianKernel(int rows, int cols, float sigma, float[] dest) {
+ if ((rows & 1) == 0) {
+ throw new IllegalArgumentException("rows must be an odd number");
+ }
+ if ((cols & 1) == 0) {
+ throw new IllegalArgumentException("cols must be an odd number");
+ }
+ if (dest == null) {
+ throw new IllegalArgumentException("dest must not be null");
+ }
+ if (dest.length < rows * cols) {
+ throw new IllegalArgumentException("dest must have a size of at least " + (rows * cols));
+ }
+ float sum = 0.0f;
+ for (int i = 0, y = -(rows - 1) / 2; y <= (rows - 1) / 2; y++) {
+ for (int x = -(cols - 1) / 2; x <= (cols - 1) / 2; x++, i++) {
+ float k = (float) Math.exp(-(y * y + x * x) / (2.0 * sigma * sigma));
+ dest[i] = k;
+ sum += k;
+ }
+ }
+ for (int i = 0; i < rows * cols; i++) {
+ dest[i] = dest[i] / sum;
+ }
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Math.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Math.java
new file mode 100644
index 000000000..8dc6669e6
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/Math.java
@@ -0,0 +1,64 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+/**
+ * Internal Math class used by the sampling package.
+ *
+ * @author Kai Burjack
+ */
+class Math extends com.jozufozu.flywheel.repack.joml.Math {
+
+ static final double PI = java.lang.Math.PI;
+ static final double PI2 = PI * 2.0;
+ static final double PIHalf = PI * 0.5;
+ private static final double ONE_OVER_PI = 1.0 / PI;
+ private static final double s5 = Double.longBitsToDouble(4523227044276562163L);
+ private static final double s4 = Double.longBitsToDouble(-4671934770969572232L);
+ private static final double s3 = Double.longBitsToDouble(4575957211482072852L);
+ private static final double s2 = Double.longBitsToDouble(-4628199223918090387L);
+ private static final double s1 = Double.longBitsToDouble(4607182418589157889L);
+
+ /**
+ * Reference: http://www.java-gaming.org/
+ *
+ * @author roquendm
+ */
+ static double sin_roquen_9(double v) {
+ double i = java.lang.Math.rint(v * ONE_OVER_PI);
+ double x = v - i * Math.PI;
+ double qs = 1 - 2 * ((int) i & 1);
+ double x2 = x * x;
+ double r;
+ x = qs * x;
+ r = s5;
+ r = r * x2 + s4;
+ r = r * x2 + s3;
+ r = r * x2 + s2;
+ r = r * x2 + s1;
+ return x * r;
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/PoissonSampling.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/PoissonSampling.java
new file mode 100644
index 000000000..550d74aaf
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/PoissonSampling.java
@@ -0,0 +1,161 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+import java.util.ArrayList;
+
+import com.jozufozu.flywheel.repack.joml.Random;
+import com.jozufozu.flywheel.repack.joml.Vector2f;
+
+/**
+ * Generates Poisson samples.
+ *
+ * The algorithm implemented here is based on Fast Poisson Disk Sampling in Arbitrary
+ * Dimensions.
+ *
+ * @author Kai Burjack
+ */
+public class PoissonSampling {
+
+ /**
+ * Generates Poisson samples on a disk.
+ *
+ * The algorithm implemented here is based on Fast Poisson Disk Sampling in Arbitrary
+ * Dimensions.
+ *
+ * @author Kai Burjack
+ */
+ public static class Disk {
+
+ private final Vector2f[] grid;
+ private final float diskRadius;
+ private final float diskRadiusSquared;
+ private final float minDist;
+ private final float minDistSquared;
+ private final float cellSize;
+ private final int numCells;
+ private final Random rnd;
+ private final ArrayList processList;
+
+ /**
+ * Create a new instance of {@link Disk} which computes poisson-distributed samples on a disk with the given radius diskRadius
and notifies the given
+ * callback
for each found sample point.
+ *
+ * The samples are distributed evenly on the disk with a minimum distance to one another of at least minDist
.
+ *
+ * @param seed
+ * the seed to initialize the random number generator with
+ * @param diskRadius
+ * the disk radius
+ * @param minDist
+ * the minimum distance between any two generated samples
+ * @param k
+ * determines how many samples are tested before rejection. Higher values produce better results. Typical values are 20 to 30
+ * @param callback
+ * will be notified about each sample point
+ */
+ public Disk(long seed, float diskRadius, float minDist, int k, Callback2d callback) {
+ this.diskRadius = diskRadius;
+ this.diskRadiusSquared = diskRadius * diskRadius;
+ this.minDist = minDist;
+ this.minDistSquared = minDist * minDist;
+ this.rnd = new Random(seed);
+ this.cellSize = minDist / (float) Math.sqrt(2.0);
+ this.numCells = (int) ((diskRadius * 2) / cellSize) + 1;
+ this.grid = new Vector2f[numCells * numCells];
+ this.processList = new ArrayList();
+ compute(k, callback);
+ }
+
+ private void compute(int k, Callback2d callback) {
+ float x, y;
+ do {
+ x = rnd.nextFloat() * 2.0f - 1.0f;
+ y = rnd.nextFloat() * 2.0f - 1.0f;
+ } while (x * x + y * y > 1.0f);
+ Vector2f initial = new Vector2f(x, y);
+ processList.add(initial);
+ callback.onNewSample(initial.x, initial.y);
+ insert(initial);
+ while (!processList.isEmpty()) {
+ int i = rnd.nextInt(processList.size());
+ Vector2f sample = (Vector2f) processList.get(i);
+ boolean found = false;
+ search: for (int s = 0; s < k; s++) {
+ float angle = rnd.nextFloat() * (float) Math.PI2;
+ float radius = minDist * (rnd.nextFloat() + 1.0f);
+ x = (float) (radius * Math.sin_roquen_9(angle + Math.PIHalf));
+ y = (float) (radius * Math.sin_roquen_9(angle));
+ x += sample.x;
+ y += sample.y;
+ if (x * x + y * y > diskRadiusSquared)
+ continue search;
+ if (!searchNeighbors(x, y)) {
+ found = true;
+ callback.onNewSample(x, y);
+ Vector2f f = new Vector2f(x, y);
+ processList.add(f);
+ insert(f);
+ break;
+ }
+ }
+ if (!found) {
+ processList.remove(i);
+ }
+ }
+ }
+
+ private boolean searchNeighbors(float px, float py) {
+ int row = (int) ((py + diskRadius) / cellSize);
+ int col = (int) ((px + diskRadius) / cellSize);
+ if (grid[row * numCells + col] != null)
+ return true;
+ int minX = Math.max(0, col - 1);
+ int minY = Math.max(0, row - 1);
+ int maxX = Math.min(col + 1, numCells - 1);
+ int maxY = Math.min(row + 1, numCells - 1);
+ for (int y = minY; y <= maxY; y++) {
+ for (int x = minX; x <= maxX; x++) {
+ Vector2f v = grid[y * numCells + x];
+ if (v != null) {
+ float dx = v.x - px;
+ float dy = v.y - py;
+ if (dx * dx + dy * dy < minDistSquared) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private void insert(Vector2f p) {
+ int row = (int) ((p.y + diskRadius) / cellSize);
+ int col = (int) ((p.x + diskRadius) / cellSize);
+ grid[row * numCells + col] = p;
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/SpiralSampling.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/SpiralSampling.java
new file mode 100644
index 000000000..2a1c0a77f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/SpiralSampling.java
@@ -0,0 +1,101 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+import com.jozufozu.flywheel.repack.joml.Random;
+
+/**
+ * Creates samples on a spiral around a center point.
+ *
+ * @author Kai Burjack
+ */
+public class SpiralSampling {
+ private final Random rnd;
+
+ /**
+ * Create a new instance of {@link SpiralSampling} and initialize the random number generator with the given seed
.
+ *
+ * @param seed
+ * the seed to initialize the random number generator with
+ */
+ public SpiralSampling(long seed) {
+ rnd = new Random(seed);
+ }
+
+ /**
+ * Create numSamples
number of samples on a spiral with maximum radius radius
around the center using numRotations
number of rotations
+ * along the spiral, and call the given callback
for each sample generated.
+ *
+ * The generated sample points are distributed with equal angle differences around the spiral, so they concentrate towards the center.
+ *
+ * @param radius
+ * the maximum radius of the spiral
+ * @param numRotations
+ * the number of rotations of the spiral
+ * @param numSamples
+ * the number of samples to generate
+ * @param callback
+ * will be called for each sample generated
+ */
+ public void createEquiAngle(float radius, int numRotations, int numSamples, Callback2d callback) {
+ for (int sample = 0; sample < numSamples; sample++) {
+ float angle = 2.0f * (float) Math.PI * (sample * numRotations) / numSamples;
+ float r = radius * sample / (numSamples - 1);
+ float x = (float) Math.sin_roquen_9(angle + 0.5f * (float) Math.PI) * r;
+ float y = (float) Math.sin_roquen_9(angle) * r;
+ callback.onNewSample(x, y);
+ }
+ }
+
+ /**
+ * Create numSamples
number of samples on a spiral with maximum radius radius
around the center using numRotations
number of rotations
+ * along the spiral, and call the given callback
for each sample generated.
+ *
+ * The generated sample points are distributed with equal angle differences around the spiral, so they concentrate towards the center.
+ *
+ * Additionally, the radius of each sample point is jittered by the given jitter
factor.
+ *
+ * @param radius
+ * the maximum radius of the spiral
+ * @param numRotations
+ * the number of rotations of the spiral
+ * @param numSamples
+ * the number of samples to generate
+ * @param jitter
+ * the factor by which the radius of each sample point is jittered. Possible values are [0..1]
+ * @param callback
+ * will be called for each sample generated
+ */
+ public void createEquiAngle(float radius, int numRotations, int numSamples, float jitter, Callback2d callback) {
+ float spacing = radius / numRotations;
+ for (int sample = 0; sample < numSamples; sample++) {
+ float angle = 2.0f * (float) Math.PI * (sample * numRotations) / numSamples;
+ float r = radius * sample / (numSamples - 1) + (rnd.nextFloat() * 2.0f - 1.0f) * spacing * jitter;
+ float x = (float) Math.sin_roquen_9(angle + 0.5f * (float) Math.PI) * r;
+ float y = (float) Math.sin_roquen_9(angle) * r;
+ callback.onNewSample(x, y);
+ }
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/StratifiedSampling.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/StratifiedSampling.java
new file mode 100644
index 000000000..8f57894c3
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/StratifiedSampling.java
@@ -0,0 +1,93 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+import com.jozufozu.flywheel.repack.joml.Random;
+
+/**
+ * Creates samples on a unit quad using an NxN strata grid.
+ *
+ * @author Kai Burjack
+ */
+public class StratifiedSampling {
+
+ private final Random rnd;
+
+ /**
+ * Create a new instance of {@link StratifiedSampling} and initialize the random number generator with the given
+ * seed
.
+ *
+ * @param seed
+ * the seed to initialize the random number generator with
+ */
+ public StratifiedSampling(long seed) {
+ this.rnd = new Random(seed);
+ }
+
+ /**
+ * Generate n * n
random sample positions in the unit square of x, y = [-1..+1]
.
+ *
+ * Each sample within its stratum is distributed randomly.
+ *
+ * @param n
+ * the number of strata in each dimension
+ * @param callback
+ * will be called for each generated sample position
+ */
+ public void generateRandom(int n, Callback2d callback) {
+ for (int y = 0; y < n; y++) {
+ for (int x = 0; x < n; x++) {
+ float sampleX = (rnd.nextFloat() / n + (float) x / n) * 2.0f - 1.0f;
+ float sampleY = (rnd.nextFloat() / n + (float) y / n) * 2.0f - 1.0f;
+ callback.onNewSample(sampleX, sampleY);
+ }
+ }
+ }
+
+ /**
+ * Generate n * n
random sample positions in the unit square of x, y = [-1..+1]
.
+ *
+ * Each sample within its stratum is confined to be within [-centering/2..1-centering]
of its stratum.
+ *
+ * @param n
+ * the number of strata in each dimension
+ * @param centering
+ * determines how much the random samples in each stratum are confined to be near the center of the
+ * stratum. Possible values are [0..1]
+ * @param callback
+ * will be called for each generated sample position
+ */
+ public void generateCentered(int n, float centering, Callback2d callback) {
+ float start = centering * 0.5f;
+ float end = 1.0f - centering;
+ for (int y = 0; y < n; y++) {
+ for (int x = 0; x < n; x++) {
+ float sampleX = ((start + rnd.nextFloat() * end) / n + (float) x / n) * 2.0f - 1.0f;
+ float sampleY = ((start + rnd.nextFloat() * end) / n + (float) y / n) * 2.0f - 1.0f;
+ callback.onNewSample(sampleX, sampleY);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/UniformSampling.java b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/UniformSampling.java
new file mode 100644
index 000000000..c6551ecf3
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/UniformSampling.java
@@ -0,0 +1,121 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2016-2021 JOML
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.jozufozu.flywheel.repack.joml.sampling;
+
+import com.jozufozu.flywheel.repack.joml.Random;
+
+/**
+ * Generates uniform samples.
+ *
+ * @author Kai Burjack
+ */
+public class UniformSampling {
+
+ /**
+ * Generates uniform samples on a unit disk.
+ *
+ * @author Kai Burjack
+ */
+ public static class Disk {
+ private final Random rnd;
+
+ /**
+ * Create a new instance of {@link Disk}, initialize the random number generator with the given seed
and generate numSamples
number of sample
+ * positions on the unit disk, and call the given callback
for each sample generate.
+ *
+ * @param seed
+ * the seed to initialize the random number generator with
+ * @param numSamples
+ * the number of samples to generate
+ * @param callback
+ * will be called for each sample generated
+ */
+ public Disk(long seed, int numSamples, Callback2d callback) {
+ this.rnd = new Random(seed);
+ generate(numSamples, callback);
+ }
+
+ private void generate(int numSamples, Callback2d callback) {
+ for (int i = 0; i < numSamples; i++) {
+ float r = rnd.nextFloat();
+ float a = rnd.nextFloat() * 2.0f * (float) Math.PI;
+ float sqrtR = (float) Math.sqrt(r);
+ float x = sqrtR * (float) Math.sin_roquen_9(a + 0.5 * Math.PI);
+ float y = sqrtR * (float) Math.sin_roquen_9(a);
+ callback.onNewSample(x, y);
+ }
+ }
+ }
+
+ /**
+ * Generates uniform samples on a unit sphere.
+ *
+ * @author Kai Burjack
+ */
+ public static class Sphere {
+ private final Random rnd;
+
+ /**
+ * Create a new instance of {@link Sphere}, initialize the random number generator with the given seed
and generate numSamples
number of sample
+ * positions on the unit sphere, and call the given callback
for each sample generate.
+ *
+ * @param seed
+ * the seed to initialize the random number generator with
+ * @param numSamples
+ * the number of samples to generate
+ * @param callback
+ * will be called for each sample generated
+ */
+ public Sphere(long seed, int numSamples, Callback3d callback) {
+ this.rnd = new Random(seed);
+ generate(numSamples, callback);
+ }
+
+ /**
+ * Create numSamples
number of samples which are uniformly distributed on a unit sphere, and call the given callback
for each sample generated.
+ *
+ * Reference: http://mathworld.wolfram.com/
+ *
+ * @param numSamples
+ * the number of samples to generate
+ * @param callback
+ * will be called for each sample generated
+ */
+ public void generate(int numSamples, Callback3d callback) {
+ for (int i = 0; i < numSamples;) {
+ float x1 = rnd.nextFloat() * 2.0f - 1.0f;
+ float x2 = rnd.nextFloat() * 2.0f - 1.0f;
+ if (x1 * x1 + x2 * x2 >= 1.0f)
+ continue;
+ float sqrt = (float) Math.sqrt(1.0 - x1 * x1 - x2 * x2);
+ float x = 2 * x1 * sqrt;
+ float y = 2 * x2 * sqrt;
+ float z = 1.0f - 2.0f * (x1 * x1 + x2 * x2);
+ callback.onNewSample(x, y, z);
+ i++;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/package.html b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/package.html
new file mode 100644
index 000000000..be323f5b9
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/repack/joml/sampling/package.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+Contains classes for generating sampling patterns.
+
+
diff --git a/src/main/java/com/jozufozu/flywheel/util/AngleHelper.java b/src/main/java/com/jozufozu/flywheel/util/AngleHelper.java
deleted file mode 100644
index a89f8bf87..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/AngleHelper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import net.minecraft.core.Direction;
-import net.minecraft.core.Direction.Axis;
-
-public class AngleHelper {
-
- public static float horizontalAngle(Direction facing) {
- if (facing.getAxis()
- .isVertical()) {
- return 0;
- }
- float angle = facing.toYRot();
- if (facing.getAxis() == Axis.X) angle = -angle;
- return angle;
- }
-
- public static float verticalAngle(Direction facing) {
- return facing == Direction.UP ? -90 : facing == Direction.DOWN ? 90 : 0;
- }
-
- public static float rad(double angle) {
- if (angle == 0) return 0;
- return (float) (angle / 180 * Math.PI);
- }
-
- public static float deg(double angle) {
- if (angle == 0) return 0;
- return (float) (angle * 180 / Math.PI);
- }
-
- public static float angleLerp(double pct, double current, double target) {
- return (float) (current + getShortestAngleDiff(current, target) * pct);
- }
-
- public static float getShortestAngleDiff(double current, double target) {
- current = current % 360;
- target = target % 360;
- return (float) (((((target - current) % 360) + 540) % 360) - 180);
- }
-
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java b/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java
index c16da14d8..20ed918df 100644
--- a/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java
+++ b/src/main/java/com/jozufozu/flywheel/util/AnimationTickHolder.java
@@ -4,22 +4,22 @@ import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor;
import net.minecraft.client.Minecraft;
+/**
+ * Static access to tick-count and partialTick time, accounting for pausing.
+ */
public class AnimationTickHolder {
+ // Wrap around every 24 hours to maintain floating point accuracy.
+ private static final int wrappingInterval = 1_728_000;
private static int ticks;
private static int paused_ticks;
- public static void reset() {
- ticks = 0;
- paused_ticks = 0;
- }
-
public static void tick() {
if (!Minecraft.getInstance()
.isPaused()) {
- ticks = (ticks + 1) % 1_728_000; // wrap around every 24 hours so we maintain enough floating point precision
+ ticks = (ticks + 1) % wrappingInterval;
} else {
- paused_ticks = (paused_ticks + 1) % 1_728_000;
+ paused_ticks = (paused_ticks + 1) % wrappingInterval;
}
}
@@ -39,4 +39,10 @@ public class AnimationTickHolder {
Minecraft mc = Minecraft.getInstance();
return (mc.isPaused() ? ((PausedPartialTickAccessor) mc).flywheel$getPartialTicksPaused() : mc.getFrameTime());
}
+
+ // Unused but might be useful for debugging.
+ public static void _reset() {
+ ticks = 0;
+ paused_ticks = 0;
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/AttribUtil.java b/src/main/java/com/jozufozu/flywheel/util/AttribUtil.java
index eb1c7aa89..b50fe47a3 100644
--- a/src/main/java/com/jozufozu/flywheel/util/AttribUtil.java
+++ b/src/main/java/com/jozufozu/flywheel/util/AttribUtil.java
@@ -2,6 +2,7 @@ package com.jozufozu.flywheel.util;
import org.lwjgl.opengl.GL20;
+// TODO: move this functionality into GlVertexArray and track it
public class AttribUtil {
public static void enableArrays(int count) {
diff --git a/src/main/java/com/jozufozu/flywheel/util/BakedQuadWrapper.java b/src/main/java/com/jozufozu/flywheel/util/BakedQuadWrapper.java
deleted file mode 100644
index a997504cf..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/BakedQuadWrapper.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import com.jozufozu.flywheel.fabric.helper.VertexFormatHelper;
-import com.mojang.blaze3d.vertex.DefaultVertexFormat;
-import com.mojang.blaze3d.vertex.VertexFormat;
-import com.mojang.blaze3d.vertex.VertexFormatElement;
-import com.mojang.math.Vector3f;
-
-import net.minecraft.client.renderer.block.model.BakedQuad;
-import net.minecraft.world.phys.Vec2;
-
-public class BakedQuadWrapper {
- private final FormatCache formatCache = new FormatCache();
- private BakedQuad quad;
- private int[] vertexData;
-
- public BakedQuadWrapper() {
- }
-
- public BakedQuadWrapper(BakedQuad quad) {
- this.quad = quad;
- this.vertexData = quad.getVertices();
- }
-
- public void setQuad(BakedQuad quad) {
- this.quad = quad;
- this.vertexData = this.quad.getVertices();
- }
-
- public static BakedQuadWrapper of(BakedQuad quad) {
- return new BakedQuadWrapper(quad);
- }
-
- public void refreshFormat() {
- formatCache.refresh();
- }
-
- public BakedQuad getQuad() {
- return quad;
- }
-
- public void clear() {
- quad = null;
- vertexData = null;
- }
-
- // Getters
-
- public float getPosX(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.position]);
- }
-
- public float getPosY(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.position + 1]);
- }
-
- public float getPosZ(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.position + 2]);
- }
-
- public Vector3f getPos(int vertexIndex) {
- return new Vector3f(getPosX(vertexIndex), getPosY(vertexIndex), getPosZ(vertexIndex));
- }
-
- public void copyPos(int vertexIndex, Vector3f pos) {
- pos.set(getPosX(vertexIndex), getPosY(vertexIndex), getPosZ(vertexIndex));
- }
-
- public int getColor(int vertexIndex) {
- return vertexData[vertexIndex * formatCache.vertexSize + formatCache.color];
- }
-
- public float getTexU(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.texture]);
- }
-
- public float getTexV(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.texture + 1]);
- }
-
- public Vec2 getTex(int vertexIndex) {
- return new Vec2(getTexU(vertexIndex), getTexV(vertexIndex));
- }
-
- public int getLight(int vertexIndex) {
- return vertexData[vertexIndex * formatCache.vertexSize + formatCache.light];
- }
-
- public float getNormalX(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.normal]);
- }
-
- public float getNormalY(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.normal + 1]);
- }
-
- public float getNormalZ(int vertexIndex) {
- return Float.intBitsToFloat(vertexData[vertexIndex * formatCache.vertexSize + formatCache.normal + 2]);
- }
-
- public Vector3f getNormal(int vertexIndex) {
- return new Vector3f(getNormalX(vertexIndex), getNormalY(vertexIndex), getNormalZ(vertexIndex));
- }
-
- public void copyNormal(int vertexIndex, Vector3f normal) {
- normal.set(getNormalX(vertexIndex), getNormalY(vertexIndex), getNormalZ(vertexIndex));
- }
-
- // Setters
-
- public void setPosX(int vertexIndex, float x) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.position] = Float.floatToRawIntBits(x);
- }
-
- public void setPosY(int vertexIndex, float y) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.position + 1] = Float.floatToRawIntBits(y);
- }
-
- public void setPosZ(int vertexIndex, float z) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.position + 2] = Float.floatToRawIntBits(z);
- }
-
- public void setPos(int vertexIndex, float x, float y, float z) {
- setPosX(vertexIndex, x);
- setPosY(vertexIndex, y);
- setPosZ(vertexIndex, z);
- }
-
- public void setPos(int vertexIndex, Vector3f pos) {
- setPos(vertexIndex, pos.x(), pos.y(), pos.z());
- }
-
- public void setColor(int vertexIndex, int color) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.color] = color;
- }
-
- public void setTexU(int vertexIndex, float u) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.texture] = Float.floatToRawIntBits(u);
- }
-
- public void setTexV(int vertexIndex, float v) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.texture + 1] = Float.floatToRawIntBits(v);
- }
-
- public void setTex(int vertexIndex, float u, float v) {
- setTexU(vertexIndex, u);
- setTexV(vertexIndex, v);
- }
-
- public void setTex(int vertexIndex, Vec2 tex) {
- setTex(vertexIndex, tex.x, tex.y);
- }
-
- public void setLight(int vertexIndex, int light) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.light] = light;
- }
-
- public void setNormalX(int vertexIndex, float normalX) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.normal] = Float.floatToRawIntBits(normalX);
- }
-
- public void setNormalY(int vertexIndex, float normalY) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.normal + 1] = Float.floatToRawIntBits(normalY);
- }
-
- public void setNormalZ(int vertexIndex, float normalZ) {
- vertexData[vertexIndex * formatCache.vertexSize + formatCache.normal + 2] = Float.floatToRawIntBits(normalZ);
- }
-
- public void setNormal(int vertexIndex, float normalX, float normalY, float normalZ) {
- setNormalX(vertexIndex, normalX);
- setNormalY(vertexIndex, normalY);
- setNormalZ(vertexIndex, normalZ);
- }
-
- public void setNormal(int vertexIndex, Vector3f normal) {
- setNormal(vertexIndex, normal.x(), normal.y(), normal.z());
- }
-
- private static class FormatCache {
- private static final VertexFormat FORMAT = DefaultVertexFormat.BLOCK;
-
- public FormatCache() {
- refresh();
- }
-
- // Integer size
- public int vertexSize;
-
- // Element integer offsets
- public int position;
- public int color;
- public int texture;
- public int light;
- public int normal;
-
- public void refresh() {
- vertexSize = FORMAT.getIntegerSize();
- for (int elementId = 0; elementId < FORMAT.getElements()
- .size(); elementId++) {
- VertexFormatElement element = FORMAT.getElements()
- .get(elementId);
- int intOffset = VertexFormatHelper.getOffset(FORMAT, elementId) / Integer.BYTES;
- if (element.getUsage() == VertexFormatElement.Usage.POSITION) {
- position = intOffset;
- } else if (element.getUsage() == VertexFormatElement.Usage.COLOR) {
- color = intOffset;
- } else if (element.getUsage() == VertexFormatElement.Usage.UV) {
- if (element.getIndex() == 0) {
- texture = intOffset;
- } else if (element.getIndex() == 2) {
- light = intOffset;
- }
- } else if (element.getUsage() == VertexFormatElement.Usage.NORMAL) {
- normal = intOffset;
- }
- }
- }
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/ChunkUtil.java b/src/main/java/com/jozufozu/flywheel/util/ChunkUtil.java
deleted file mode 100644
index e6612b054..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/ChunkUtil.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import javax.annotation.Nullable;
-
-import net.minecraft.world.level.chunk.LevelChunk;
-import net.minecraft.world.level.chunk.LevelChunkSection;
-
-public class ChunkUtil {
-
- public static boolean isValidSection(@Nullable LevelChunk chunk, int sectionY) {
- if (chunk == null) return false;
-
- // TODO: 1.17
- LevelChunkSection[] sections = chunk.getSections();
-
- return sectionY >= 0 && sectionY < sections.length;
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/Color.java b/src/main/java/com/jozufozu/flywheel/util/Color.java
new file mode 100644
index 000000000..0a21b84bd
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/util/Color.java
@@ -0,0 +1,309 @@
+package com.jozufozu.flywheel.util;
+
+import java.util.function.UnaryOperator;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.hash.Hashing;
+import com.mojang.math.Vector3f;
+
+import net.minecraft.util.Mth;
+import net.minecraft.world.phys.Vec3;
+
+@SuppressWarnings("PointlessBitwiseExpression")
+public class Color {
+ public final static Color TRANSPARENT_BLACK = new Color(0, 0, 0, 0).setImmutable();
+ public final static Color BLACK = new Color(0, 0, 0).setImmutable();
+ public final static Color WHITE = new Color(255, 255, 255).setImmutable();
+ public final static Color RED = new Color(255, 0, 0).setImmutable();
+ public final static Color GREEN = new Color(0, 255, 0).setImmutable();
+ public final static Color SPRING_GREEN = new Color(0, 255, 187).setImmutable();
+
+ protected boolean mutable = true;
+ protected int value;
+
+ public Color(int r, int g, int b) {
+ this(r, g, b, 0xff);
+ }
+
+ public Color(int r, int g, int b, int a) {
+ value = ((a & 0xff) << 24) |
+ ((r & 0xff) << 16) |
+ ((g & 0xff) << 8) |
+ ((b & 0xff) << 0);
+ }
+
+ public Color(float r, float g, float b, float a) {
+ this(
+ (int) (0.5 + 0xff * Mth.clamp(r, 0, 1)),
+ (int) (0.5 + 0xff * Mth.clamp(g, 0, 1)),
+ (int) (0.5 + 0xff * Mth.clamp(b, 0, 1)),
+ (int) (0.5 + 0xff * Mth.clamp(a, 0, 1))
+ );
+ }
+
+ public Color(int rgba) {
+ value = rgba;
+ }
+
+ public Color(int rgb, boolean hasAlpha) {
+ if (hasAlpha) {
+ value = rgb;
+ } else {
+ value = rgb | 0xff_000000;
+ }
+ }
+
+ public Color copy() {
+ return copy(true);
+ }
+
+ public Color copy(boolean mutable) {
+ if (mutable)
+ return new Color(value);
+ else
+ return new Color(value).setImmutable();
+ }
+
+ /**
+ * Mark this color as immutable. Attempting to mutate this color in the future
+ * will instead cause a copy to be created that can me modified.
+ */
+ public Color setImmutable() {
+ this.mutable = false;
+ return this;
+ }
+
+ /**
+ * @return the red component in the range 0-255.
+ * @see #getRGB
+ */
+ public int getRed() {
+ return (getRGB() >> 16) & 0xff;
+ }
+
+ /**
+ * @return the green component in the range 0-255.
+ * @see #getRGB
+ */
+ public int getGreen() {
+ return (getRGB() >> 8) & 0xff;
+ }
+
+ /**
+ * @return the blue component in the range 0-255.
+ * @see #getRGB
+ */
+ public int getBlue() {
+ return (getRGB() >> 0) & 0xff;
+ }
+
+ /**
+ * @return the alpha component in the range 0-255.
+ * @see #getRGB
+ */
+ public int getAlpha() {
+ return (getRGB() >> 24) & 0xff;
+ }
+
+ /**
+ * @return the red component in the range 0-1f.
+ */
+ public float getRedAsFloat() {
+ return getRed() / 255f;
+ }
+
+ /**
+ * @return the green component in the range 0-1f.
+ */
+ public float getGreenAsFloat() {
+ return getGreen() / 255f;
+ }
+
+ /**
+ * @return the blue component in the range 0-1f.
+ */
+ public float getBlueAsFloat() {
+ return getBlue() / 255f;
+ }
+
+ /**
+ * @return the alpha component in the range 0-1f.
+ */
+ public float getAlphaAsFloat() {
+ return getAlpha() / 255f;
+ }
+
+ /**
+ * Returns the RGB value representing this color
+ * (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue).
+ * @return the RGB value of the color
+ */
+ public int getRGB() {
+ return value;
+ }
+
+ public Vec3 asVector() {
+ return new Vec3(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
+ }
+
+ public Vector3f asVectorF() {
+ return new Vector3f(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
+ }
+
+ public Color setRed(int r) {
+ return ensureMutable().setRedUnchecked(r);
+ }
+
+ public Color setGreen(int g) {
+ return ensureMutable().setGreenUnchecked(g);
+ }
+
+ public Color setBlue(int b) {
+ return ensureMutable().setBlueUnchecked(b);
+ }
+
+ public Color setAlpha(int a) {
+ return ensureMutable().setAlphaUnchecked(a);
+ }
+
+ public Color setRed(float r) {
+ return ensureMutable().setRedUnchecked((int) (0xff * Mth.clamp(r, 0, 1)));
+ }
+
+ public Color setGreen(float g) {
+ return ensureMutable().setGreenUnchecked((int) (0xff * Mth.clamp(g, 0, 1)));
+ }
+
+ public Color setBlue(float b) {
+ return ensureMutable().setBlueUnchecked((int) (0xff * Mth.clamp(b, 0, 1)));
+ }
+
+ public Color setAlpha(float a) {
+ return ensureMutable().setAlphaUnchecked((int) (0xff * Mth.clamp(a, 0, 1)));
+ }
+
+ public Color scaleAlpha(float factor) {
+ return ensureMutable().setAlphaUnchecked((int) (getAlpha() * Mth.clamp(factor, 0, 1)));
+ }
+
+ public Color mixWith(Color other, float weight) {
+ return ensureMutable()
+ .setRedUnchecked((int) (getRed() + (other.getRed() - getRed()) * weight))
+ .setGreenUnchecked((int) (getGreen() + (other.getGreen() - getGreen()) * weight))
+ .setBlueUnchecked((int) (getBlue() + (other.getBlue() - getBlue()) * weight))
+ .setAlphaUnchecked((int) (getAlpha() + (other.getAlpha() - getAlpha()) * weight));
+ }
+
+ public Color darker() {
+ int a = getAlpha();
+ return ensureMutable().mixWith(BLACK, .25f).setAlphaUnchecked(a);
+ }
+
+ public Color brighter() {
+ int a = getAlpha();
+ return ensureMutable().mixWith(WHITE, .25f).setAlphaUnchecked(a);
+ }
+
+ public Color setValue(int value) {
+ return ensureMutable().setValueUnchecked(value);
+ }
+
+ public Color modifyValue(UnaryOperator function) {
+ int newValue = function.apply(value);
+ if (newValue == value)
+ return this;
+
+ return ensureMutable().setValueUnchecked(newValue);
+ }
+
+ // ********* //
+
+ protected Color ensureMutable() {
+ if (this.mutable)
+ return this;
+
+ return new Color(this.value);
+ }
+
+ protected Color setRedUnchecked(int r) {
+ this.value = (this.value & 0xff_00ffff) | ((r & 0xff) << 16);
+ return this;
+ }
+
+ protected Color setGreenUnchecked(int g) {
+ this.value = (this.value & 0xff_ff00ff) | ((g & 0xff) << 8);
+ return this;
+ }
+
+ protected Color setBlueUnchecked(int b) {
+ this.value = (this.value & 0xff_ffff00) | ((b & 0xff) << 0);
+ return this;
+ }
+
+ protected Color setAlphaUnchecked(int a) {
+ this.value = (this.value & 0x00_ffffff) | ((a & 0xff) << 24);
+ return this;
+ }
+
+ protected Color setValueUnchecked(int value) {
+ this.value = value;
+ return this;
+ }
+
+ // ********* //
+
+ public static Color mixColors(@Nonnull Color c1, @Nonnull Color c2, float w) {
+ return new Color(
+ (int) (c1.getRed() + (c2.getRed() - c1.getRed()) * w),
+ (int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * w),
+ (int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * w),
+ (int) (c1.getAlpha() + (c2.getAlpha() - c1.getAlpha()) * w)
+ );
+ }
+
+ public static int mixColors(int color1, int color2, float w) {
+ int a1 = (color1 >> 24);
+ int r1 = (color1 >> 16) & 0xFF;
+ int g1 = (color1 >> 8) & 0xFF;
+ int b1 = color1 & 0xFF;
+ int a2 = (color2 >> 24);
+ int r2 = (color2 >> 16) & 0xFF;
+ int g2 = (color2 >> 8) & 0xFF;
+ int b2 = color2 & 0xFF;
+
+ return
+ ((int) (a1 + (a2 - a1) * w) << 24) +
+ ((int) (r1 + (r2 - r1) * w) << 16) +
+ ((int) (g1 + (g2 - g1) * w) << 8) +
+ ((int) (b1 + (b2 - b1) * w) << 0);
+ }
+
+ public static Color rainbowColor(int timeStep) {
+ int localTimeStep = Math.abs(timeStep) % 1536;
+ int timeStepInPhase = localTimeStep % 256;
+ int phaseBlue = localTimeStep / 256;
+ int red = colorInPhase(phaseBlue + 4, timeStepInPhase);
+ int green = colorInPhase(phaseBlue + 2, timeStepInPhase);
+ int blue = colorInPhase(phaseBlue, timeStepInPhase);
+ return new Color(red, green, blue);
+ }
+
+ private static int colorInPhase(int phase, int progress) {
+ phase = phase % 6;
+ if (phase <= 1)
+ return 0;
+ if (phase == 2)
+ return progress;
+ if (phase <= 4)
+ return 255;
+ else
+ return 255 - progress;
+ }
+
+ public static Color generateFromLong(long l) {
+ return rainbowColor(Hashing.crc32().hashLong(l).asInt())
+ .mixWith(WHITE, 0.5f);
+ }
+
+}
diff --git a/src/main/java/com/jozufozu/flywheel/util/MatrixWrite.java b/src/main/java/com/jozufozu/flywheel/util/MatrixWrite.java
new file mode 100644
index 000000000..0619d0793
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/util/MatrixWrite.java
@@ -0,0 +1,17 @@
+package com.jozufozu.flywheel.util;
+
+import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
+
+/**
+ * @see com.jozufozu.flywheel.mixin.matrix.Matrix3fMixin
+ * @see com.jozufozu.flywheel.mixin.matrix.Matrix4fMixin
+ */
+public interface MatrixWrite {
+
+ /**
+ * Write the contents of this object into sequential memory starting at the given address.
+ */
+ void flywheel$writeUnsafe(long ptr);
+
+ void flywheel$write(VecBuffer buf);
+}
diff --git a/src/main/java/com/jozufozu/flywheel/util/Pair.java b/src/main/java/com/jozufozu/flywheel/util/Pair.java
index ac3a10d83..6b3a48d7d 100644
--- a/src/main/java/com/jozufozu/flywheel/util/Pair.java
+++ b/src/main/java/com/jozufozu/flywheel/util/Pair.java
@@ -2,34 +2,14 @@ package com.jozufozu.flywheel.util;
import java.util.Objects;
-public class Pair {
-
- F first;
- S second;
-
- protected Pair(F first, S second) {
- this.first = first;
- this.second = second;
- }
+public record Pair(F first, S second) {
public static Pair of(F first, S second) {
return new Pair<>(first, second);
}
- public F getFirst() {
- return first;
- }
-
- public S getSecond() {
- return second;
- }
-
- public void setFirst(F first) {
- this.first = first;
- }
-
- public void setSecond(S second) {
- this.second = second;
+ public Pair swap() {
+ return Pair.of(second, first);
}
public Pair copy() {
@@ -39,8 +19,7 @@ public class Pair {
@Override
public boolean equals(final Object obj) {
if (obj == this) return true;
- if (obj instanceof Pair) {
- final Pair, ?> other = (Pair, ?>) obj;
+ if (obj instanceof final Pair, ?> other) {
return Objects.equals(first, other.first) && Objects.equals(second, other.second);
}
return false;
@@ -51,17 +30,13 @@ public class Pair {
return (nullHash(first) * 31) ^ nullHash(second);
}
- int nullHash(Object o) {
- return o == null ? 0 : o.hashCode();
- }
-
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}
- public Pair swap() {
- return Pair.of(second, first);
+ static int nullHash(Object o) {
+ return o == null ? 0 : o.hashCode();
}
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/RenderMath.java b/src/main/java/com/jozufozu/flywheel/util/RenderMath.java
index 3b891d683..3491e9319 100644
--- a/src/main/java/com/jozufozu/flywheel/util/RenderMath.java
+++ b/src/main/java/com/jozufozu/flywheel/util/RenderMath.java
@@ -29,4 +29,46 @@ public class RenderMath {
public static byte unb(float f) {
return (byte) Math.floor(f * 255);
}
+
+ public static int nextPowerOf2(int a) {
+ int h = Integer.highestOneBit(a);
+ return (h == a) ? h : (h << 1);
+ }
+
+ public static boolean isPowerOf2(int n) {
+ int b = n & (n - 1);
+ return b == 0 && n != 0;
+ }
+
+ public static double lengthSqr(double x, double y, double z) {
+ return x * x + y * y + z * z;
+ }
+
+ public static double length(double x, double y, double z) {
+ return Math.sqrt(lengthSqr(x, y, z));
+ }
+
+ public static float rad(double angle) {
+ if (angle == 0) return 0;
+ return (float) (angle / 180 * Math.PI);
+ }
+
+ public static float deg(double angle) {
+ if (angle == 0) return 0;
+ return (float) (angle * 180 / Math.PI);
+ }
+
+ public static float angleLerp(double pct, double current, double target) {
+ return (float) (current + getShortestAngleDiff(current, target) * pct);
+ }
+
+ public static float getShortestAngleDiff(double current, double target) {
+ current = current % 360;
+ target = target % 360;
+ return (float) (((((target - current) % 360) + 540) % 360) - 180);
+ }
+
+ public static float diffuseLight(float x, float y, float z) {
+ return Math.min(x * x * 0.6f + y * y * ((3f + y) / 4f) + z * z * 0.8f, 1f);
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/RenderUtil.java b/src/main/java/com/jozufozu/flywheel/util/RenderUtil.java
deleted file mode 100644
index 23eee5808..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/RenderUtil.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import java.util.function.Supplier;
-
-import com.jozufozu.flywheel.fabric.helper.Matrix4fHelper;
-import com.mojang.blaze3d.vertex.PoseStack;
-import com.mojang.math.Matrix4f;
-import com.mojang.math.Vector3f;
-
-import net.minecraft.core.Direction;
-
-public class RenderUtil {
-
- private static final Matrix4f IDENTITY = new Matrix4f();
- static {
- IDENTITY.setIdentity();
- }
-
- public static Matrix4f getIdentity() {
- return IDENTITY;
- }
-
- public static Matrix4f copyIdentity() {
- return IDENTITY.copy();
- }
-
- public static int nextPowerOf2(int a) {
- int h = Integer.highestOneBit(a);
- return (h == a) ? h : (h << 1);
- }
-
- public static boolean isPowerOf2(int n) {
- int b = n & (n - 1);
- return b == 0 && n != 0;
- }
-
- public static double lengthSqr(double x, double y, double z) {
- return x * x + y * y + z * z;
- }
-
- public static double length(double x, double y, double z) {
- return Math.sqrt(lengthSqr(x, y, z));
- }
-
- public static Supplier rotateToFace(Direction facing) {
- return () -> {
- PoseStack stack = new PoseStack();
- // MatrixStacker.of(stack)
- // .centre()
- // .rotateY(AngleHelper.horizontalAngle(facing))
- // .rotateX(AngleHelper.verticalAngle(facing))
- // .unCentre();
- Matrix4fHelper.setTranslation(stack.last()
- .pose(),
- 0.5f, 0.5f, 0.5f);
- stack.mulPose(Vector3f.YP.rotationDegrees(AngleHelper.horizontalAngle(facing)));
- stack.mulPose(Vector3f.XP.rotationDegrees(AngleHelper.verticalAngle(facing)));
- stack.translate(-0.5f, -0.5f, -0.5f);
- return stack;
- };
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/StreamUtil.java b/src/main/java/com/jozufozu/flywheel/util/StreamUtil.java
deleted file mode 100644
index dd1b4d70a..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/StreamUtil.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.FileChannel;
-import java.nio.channels.ReadableByteChannel;
-
-import org.lwjgl.system.MemoryUtil;
-
-public class StreamUtil {
- public static String readToString(InputStream is) {
- ByteBuffer bytebuffer = null;
-
- try {
- bytebuffer = readToBuffer(is);
- int i = bytebuffer.position();
- ((Buffer) bytebuffer).rewind();
- return MemoryUtil.memASCII(bytebuffer, i);
- } catch (IOException e) {
-
- } finally {
- if (bytebuffer != null) {
- MemoryUtil.memFree(bytebuffer);
- }
-
- }
-
- return null;
- }
-
- public static ByteBuffer readToBuffer(InputStream is) throws IOException {
- ByteBuffer bytebuffer;
- if (is instanceof FileInputStream) {
- FileInputStream fileinputstream = (FileInputStream) is;
- FileChannel filechannel = fileinputstream.getChannel();
- bytebuffer = MemoryUtil.memAlloc((int) filechannel.size() + 1);
-
- while (filechannel.read(bytebuffer) != -1) {
- }
- } else {
- bytebuffer = MemoryUtil.memAlloc(8192);
- ReadableByteChannel readablebytechannel = Channels.newChannel(is);
-
- while (readablebytechannel.read(bytebuffer) != -1) {
- if (bytebuffer.remaining() == 0) {
- bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
- }
- }
- }
-
- return bytebuffer;
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java
index b4ee5a638..9a1d5d2e9 100644
--- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java
+++ b/src/main/java/com/jozufozu/flywheel/util/StringUtil.java
@@ -1,8 +1,18 @@
package com.jozufozu.flywheel.util;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
import java.util.Arrays;
import java.util.stream.Collectors;
+import org.lwjgl.system.MemoryUtil;
+
public class StringUtil {
public static String args(String functionName, Object... args) {
@@ -20,4 +30,52 @@ public class StringUtil {
}
return value.substring(0, len);
}
+
+ public static String readToString(InputStream is) {
+ ByteBuffer bytebuffer = null;
+
+ try {
+ bytebuffer = readToBuffer(is);
+ int i = bytebuffer.position();
+ ((Buffer) bytebuffer).rewind();
+ return MemoryUtil.memASCII(bytebuffer, i);
+ } catch (IOException ignored) {
+ } finally {
+ if (bytebuffer != null) {
+ MemoryUtil.memFree(bytebuffer);
+ }
+
+ }
+
+ return null;
+ }
+
+ public static ByteBuffer readToBuffer(InputStream is) throws IOException {
+ if (is instanceof FileInputStream fileinputstream) {
+ return readFileInputStream(fileinputstream);
+ } else {
+ return readInputStream(is);
+ }
+ }
+
+ private static ByteBuffer readInputStream(InputStream is) throws IOException {
+ ByteBuffer bytebuffer = MemoryUtil.memAlloc(8192);
+ ReadableByteChannel readablebytechannel = Channels.newChannel(is);
+
+ while (readablebytechannel.read(bytebuffer) != -1) {
+ if (bytebuffer.remaining() == 0) {
+ bytebuffer = MemoryUtil.memRealloc(bytebuffer, bytebuffer.capacity() * 2);
+ }
+ }
+ return bytebuffer;
+ }
+
+ private static ByteBuffer readFileInputStream(FileInputStream fileinputstream) throws IOException {
+ FileChannel filechannel = fileinputstream.getChannel();
+ ByteBuffer bytebuffer = MemoryUtil.memAlloc((int) filechannel.size() + 1);
+
+ while (filechannel.read(bytebuffer) != -1) {
+ }
+ return bytebuffer;
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java b/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java
index ba9c4f64e..e90435078 100644
--- a/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java
+++ b/src/main/java/com/jozufozu/flywheel/util/TextureBinder.java
@@ -1,9 +1,5 @@
package com.jozufozu.flywheel.util;
-import org.lwjgl.opengl.GL32;
-
-import com.mojang.blaze3d.systems.RenderSystem;
-
import net.minecraft.client.renderer.RenderType;
/**
@@ -16,14 +12,4 @@ import net.minecraft.client.renderer.RenderType;
*/
public class TextureBinder {
- /**
- * Call this after calling {@link RenderType#setupRenderState()}.
- */
- public static void bindActiveTextures() {
- for (int i = 0; i < 12; i++) {
- int shaderTexture = RenderSystem.getShaderTexture(i);
- RenderSystem.activeTexture(GL32.GL_TEXTURE0 + i);
- RenderSystem.bindTexture(shaderTexture);
- }
- }
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/RenderTextures.java b/src/main/java/com/jozufozu/flywheel/util/Textures.java
similarity index 58%
rename from src/main/java/com/jozufozu/flywheel/util/RenderTextures.java
rename to src/main/java/com/jozufozu/flywheel/util/Textures.java
index 8ea3f12dc..f648e7cde 100644
--- a/src/main/java/com/jozufozu/flywheel/util/RenderTextures.java
+++ b/src/main/java/com/jozufozu/flywheel/util/Textures.java
@@ -2,6 +2,11 @@ package com.jozufozu.flywheel.util;
import javax.annotation.Nullable;
+import org.lwjgl.opengl.GL32;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+
+import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
/**
@@ -11,7 +16,7 @@ import net.minecraft.resources.ResourceLocation;
* Works with {@link com.jozufozu.flywheel.mixin.RenderTexturesMixin}.
*
*/
-public class RenderTextures {
+public class Textures {
private static final ResourceLocation[] shaderTextures = new ResourceLocation[12];
@@ -23,4 +28,15 @@ public class RenderTextures {
public static void _setShaderTexture(int pShaderTexture, ResourceLocation pTextureId) {
shaderTextures[pShaderTexture] = pTextureId;
}
+
+ /**
+ * Call this after calling {@link RenderType#setupRenderState()}.
+ */
+ public static void bindActiveTextures() {
+ for (int i = 0; i < 12; i++) {
+ int shaderTexture = RenderSystem.getShaderTexture(i);
+ RenderSystem.activeTexture(GL32.GL_TEXTURE0 + i);
+ RenderSystem.bindTexture(shaderTexture);
+ }
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/WriteSafe.java b/src/main/java/com/jozufozu/flywheel/util/WriteSafe.java
deleted file mode 100644
index 0fdc7f128..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/WriteSafe.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
-
-public interface WriteSafe {
- void write(VecBuffer buf);
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/WriteUnsafe.java b/src/main/java/com/jozufozu/flywheel/util/WriteUnsafe.java
deleted file mode 100644
index 7d963ee5c..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/WriteUnsafe.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.jozufozu.flywheel.util;
-
-public interface WriteUnsafe {
-
- /**
- * Write the contents of this object into sequential memory starting at the given address.
- */
- void writeUnsafe(long addr);
-}
diff --git a/src/main/java/com/jozufozu/flywheel/light/CoordinateConsumer.java b/src/main/java/com/jozufozu/flywheel/util/box/CoordinateConsumer.java
similarity index 71%
rename from src/main/java/com/jozufozu/flywheel/light/CoordinateConsumer.java
rename to src/main/java/com/jozufozu/flywheel/util/box/CoordinateConsumer.java
index b6a64eb0d..f42c5a00b 100644
--- a/src/main/java/com/jozufozu/flywheel/light/CoordinateConsumer.java
+++ b/src/main/java/com/jozufozu/flywheel/util/box/CoordinateConsumer.java
@@ -1,4 +1,4 @@
-package com.jozufozu.flywheel.light;
+package com.jozufozu.flywheel.util.box;
@FunctionalInterface
public interface CoordinateConsumer {
diff --git a/src/main/java/com/jozufozu/flywheel/light/GridAlignedBB.java b/src/main/java/com/jozufozu/flywheel/util/box/GridAlignedBB.java
similarity index 96%
rename from src/main/java/com/jozufozu/flywheel/light/GridAlignedBB.java
rename to src/main/java/com/jozufozu/flywheel/util/box/GridAlignedBB.java
index e96f9fbc7..fa6925a36 100644
--- a/src/main/java/com/jozufozu/flywheel/light/GridAlignedBB.java
+++ b/src/main/java/com/jozufozu/flywheel/util/box/GridAlignedBB.java
@@ -1,6 +1,6 @@
-package com.jozufozu.flywheel.light;
+package com.jozufozu.flywheel.util.box;
-import com.jozufozu.flywheel.util.RenderUtil;
+import com.jozufozu.flywheel.util.RenderMath;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -116,9 +116,9 @@ public class GridAlignedBB implements ImmutableBox {
int sizeY = sizeY();
int sizeZ = sizeZ();
- int newSizeX = RenderUtil.nextPowerOf2(sizeX);
- int newSizeY = RenderUtil.nextPowerOf2(sizeY);
- int newSizeZ = RenderUtil.nextPowerOf2(sizeZ);
+ int newSizeX = RenderMath.nextPowerOf2(sizeX);
+ int newSizeY = RenderMath.nextPowerOf2(sizeY);
+ int newSizeZ = RenderMath.nextPowerOf2(sizeZ);
int diffX = newSizeX - sizeX;
int diffY = newSizeY - sizeY;
@@ -136,9 +136,9 @@ public class GridAlignedBB implements ImmutableBox {
* Grow this bounding box to have power of 2 side lengths, scaling from the minimum coords.
*/
public void nextPowerOf2() {
- int sizeX = RenderUtil.nextPowerOf2(sizeX());
- int sizeY = RenderUtil.nextPowerOf2(sizeY());
- int sizeZ = RenderUtil.nextPowerOf2(sizeZ());
+ int sizeX = RenderMath.nextPowerOf2(sizeX());
+ int sizeY = RenderMath.nextPowerOf2(sizeY());
+ int sizeZ = RenderMath.nextPowerOf2(sizeZ());
maxX = minX + sizeX;
maxY = minY + sizeY;
diff --git a/src/main/java/com/jozufozu/flywheel/light/ImmutableBox.java b/src/main/java/com/jozufozu/flywheel/util/box/ImmutableBox.java
similarity index 97%
rename from src/main/java/com/jozufozu/flywheel/light/ImmutableBox.java
rename to src/main/java/com/jozufozu/flywheel/util/box/ImmutableBox.java
index 719966424..10a5c7a91 100644
--- a/src/main/java/com/jozufozu/flywheel/light/ImmutableBox.java
+++ b/src/main/java/com/jozufozu/flywheel/util/box/ImmutableBox.java
@@ -1,6 +1,6 @@
-package com.jozufozu.flywheel.light;
+package com.jozufozu.flywheel.util.box;
-import static com.jozufozu.flywheel.util.RenderUtil.isPowerOf2;
+import static com.jozufozu.flywheel.util.RenderMath.isPowerOf2;
import net.minecraft.world.phys.AABB;
diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java
index 2fa562ffa..8a354c80a 100644
--- a/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java
+++ b/src/main/java/com/jozufozu/flywheel/util/transform/MatrixTransformStack.java
@@ -1,6 +1,8 @@
package com.jozufozu.flywheel.util.transform;
import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.math.Matrix3f;
+import com.mojang.math.Matrix4f;
import com.mojang.math.Quaternion;
public class MatrixTransformStack implements TransformStack {
@@ -64,4 +66,16 @@ public class MatrixTransformStack implements TransformStack {
internal.popPose();
return this;
}
+
+ @Override
+ public TransformStack mulPose(Matrix4f pose) {
+ internal.last().pose().multiply(pose);
+ return this;
+ }
+
+ @Override
+ public TransformStack mulNormal(Matrix3f normal) {
+ internal.last().normal().mul(normal);
+ return this;
+ }
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/Transform.java b/src/main/java/com/jozufozu/flywheel/util/transform/Transform.java
new file mode 100644
index 000000000..f2ebe795f
--- /dev/null
+++ b/src/main/java/com/jozufozu/flywheel/util/transform/Transform.java
@@ -0,0 +1,36 @@
+package com.jozufozu.flywheel.util.transform;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.math.Matrix3f;
+import com.mojang.math.Matrix4f;
+import com.mojang.math.Quaternion;
+
+import net.minecraft.core.Direction;
+
+public interface Transform> extends Translate, Rotate, Scale {
+ Self mulPose(Matrix4f pose);
+
+ Self mulNormal(Matrix3f normal);
+
+ default Self transform(Matrix4f pose, Matrix3f normal) {
+ mulPose(pose);
+ return mulNormal(normal);
+ }
+
+ default Self transform(PoseStack stack) {
+ PoseStack.Pose last = stack.last();
+ return transform(last.pose(), last.normal());
+ }
+
+ default Self rotateCentered(Direction axis, float radians) {
+ translate(.5f, .5f, .5f).rotate(axis, radians)
+ .translate(-.5f, -.5f, -.5f);
+ return (Self) this;
+ }
+
+ default Self rotateCentered(Quaternion q) {
+ translate(.5f, .5f, .5f).multiply(q)
+ .translate(-.5f, -.5f, -.5f);
+ return (Self) this;
+ }
+}
diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java
index da521b69b..453953a9b 100644
--- a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java
+++ b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java
@@ -2,7 +2,7 @@ package com.jozufozu.flywheel.util.transform;
import com.mojang.blaze3d.vertex.PoseStack;
-public interface TransformStack extends Scale, Translate, Rotate, TStack {
+public interface TransformStack extends Transform, TStack {
static TransformStack cast(PoseStack stack) {
return (TransformStack) stack;
}
diff --git a/src/main/java/com/jozufozu/flywheel/util/vec/Vec3.java b/src/main/java/com/jozufozu/flywheel/util/vec/Vec3.java
deleted file mode 100644
index 4bd8e309f..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/vec/Vec3.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.jozufozu.flywheel.util.vec;
-
-import com.mojang.math.Quaternion;
-import com.mojang.math.Vector3f;
-
-public class Vec3 {
- public static final Vec3 NEGATIVE_X = new Vec3(-1.0F, 0.0F, 0.0F);
- public static final Vec3 POSITIVE_X = new Vec3(1.0F, 0.0F, 0.0F);
- public static final Vec3 NEGATIVE_Y = new Vec3(0.0F, -1.0F, 0.0F);
- public static final Vec3 POSITIVE_Y = new Vec3(0.0F, 1.0F, 0.0F);
- public static final Vec3 NEGATIVE_Z = new Vec3(0.0F, 0.0F, -1.0F);
- public static final Vec3 POSITIVE_Z = new Vec3(0.0F, 0.0F, 1.0F);
-
- private float x;
- private float y;
- private float z;
-
- public Vec3(float x, float y, float z) {
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- public float getX() {
- return x;
- }
-
- public float getY() {
- return y;
- }
-
- public float getZ() {
- return z;
- }
-
- public Vec3 multiply(Quaternion quat) {
- Vec4 vec4 = new Vec4(this, 1f);
-
- vec4.multiply(quat);
-
- return set(vec4.getX(), vec4.getY(), vec4.getZ());
- }
-
- public Vec3 copy() {
- return new Vec3(x, y, z);
- }
-
- public Vector3f convert() {
- return new Vector3f(x, y, z);
- }
-
- public Vec3 set(float x, float y, float z) {
- this.x = x;
- this.y = y;
- this.z = z;
- return this;
- }
-
- public Vec3 add(Vec3 v) {
- return add(v.x, v.y, v.z);
- }
-
- public Vec3 add(float x, float y, float z) {
- this.x += x;
- this.y += y;
- this.z += z;
- return this;
- }
-
- public Vec3 sub(Vec3 v) {
- return sub(v.x, v.y, v.z);
- }
-
- public Vec3 sub(float x, float y, float z) {
- this.x -= x;
- this.y -= y;
- this.z -= z;
- return this;
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/util/vec/Vec4.java b/src/main/java/com/jozufozu/flywheel/util/vec/Vec4.java
deleted file mode 100644
index b4f5cb663..000000000
--- a/src/main/java/com/jozufozu/flywheel/util/vec/Vec4.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.jozufozu.flywheel.util.vec;
-
-import com.mojang.math.Quaternion;
-
-public class Vec4 {
-
- private float x;
- private float y;
- private float z;
- private float w;
-
- public Vec4(float x, float y, float z, float w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- }
-
- public Vec4(Vec3 vec3) {
- this(vec3, 0);
- }
-
- public Vec4(Vec3 vec3, float w) {
- this.x = vec3.getX();
- this.y = vec3.getY();
- this.z = vec3.getZ();
- this.w = w;
- }
-
- public Vec4 multiply(Quaternion quat) {
- Quaternion quaternion = new Quaternion(quat);
- quaternion.mul(new Quaternion(this.getX(), this.getY(), this.getZ(), 0.0F));
- Quaternion quaternion1 = new Quaternion(quat);
- quaternion1.conj();
- quaternion.mul(quaternion1);
- return set(quaternion.i(), quaternion.j(), quaternion.k(), this.getW());
- }
-
- public Vec3 xyz() {
- return new Vec3(x, y, z);
- }
-
- public float getX() {
- return x;
- }
-
- public float getY() {
- return y;
- }
-
- public float getZ() {
- return z;
- }
-
- public float getW() {
- return w;
- }
-
- public Vec4 set(float x, float y, float z, float w) {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- return this;
- }
-}
diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java
index 5cfd8eb60..c66e41b63 100644
--- a/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java
+++ b/src/main/java/com/jozufozu/flywheel/vanilla/BellInstance.java
@@ -5,7 +5,7 @@ import com.jozufozu.flywheel.api.instance.IDynamicInstance;
import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
-import com.jozufozu.flywheel.core.model.ModelPart;
+import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.mojang.math.Quaternion;
import com.mojang.math.Vector3f;
diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java
index 0dddeefb7..ab1acdebf 100644
--- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java
+++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java
@@ -10,7 +10,7 @@ import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
-import com.jozufozu.flywheel.core.model.ModelPart;
+import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.mojang.math.Quaternion;
import com.mojang.math.Vector3f;
diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java
index bf53ae248..4fe3116df 100644
--- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java
+++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartInstance.java
@@ -7,7 +7,7 @@ import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.model.Model;
-import com.jozufozu.flywheel.core.model.ModelPart;
+import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import com.mojang.math.Vector3f;
diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java
index 1f3ecbfe1..a64e5b0ec 100644
--- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java
+++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java
@@ -5,7 +5,7 @@ import com.jozufozu.flywheel.api.instance.IDynamicInstance;
import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData;
-import com.jozufozu.flywheel.core.model.ModelPart;
+import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import com.mojang.math.Quaternion;
diff --git a/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl b/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl
index ae77b9b68..48e713b43 100644
--- a/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl
+++ b/src/main/resources/assets/flywheel/flywheel/shaders/data/modelvertex.glsl
@@ -1,5 +1,5 @@
struct Vertex {
vec3 pos;
- vec3 normal;
vec2 texCoords;
+ vec3 normal;
};
diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json
index 5e5f07141..b1ae23ad8 100644
--- a/src/main/resources/flywheel.mixins.json
+++ b/src/main/resources/flywheel.mixins.json
@@ -4,6 +4,8 @@
"package": "com.jozufozu.flywheel.mixin",
"compatibilityLevel": "JAVA_17",
"client": [
+ "BufferBuilderMixin",
+ "BufferUploaderAccessor",
"CancelEntityRenderMixin",
"ChunkRebuildHooksMixin",
"FixFabulousDepthMixin",
@@ -14,6 +16,7 @@
"RenderHooksMixin",
"RenderTexturesMixin",
"ShaderCloseMixin",
+ "ShaderInstanceAccessor",
"atlas.AtlasDataMixin",
"atlas.SheetDataAccessor",
"light.LightUpdateMixin",