Use external JOML

- Use JOML from its official Maven source instead of bundling classes
- Organize imports
This commit is contained in:
PepperCode1 2023-03-29 22:03:28 -07:00
parent 3900297186
commit e7fd1c6178
43 changed files with 71 additions and 43462 deletions

View file

@ -113,7 +113,7 @@ repositories {
mavenCentral()
}
// Fix for loading non-mod libraries in dev-env, used for miniball.
// Fix for loading non-mod libraries in dev-env, used for JOML and Miniball.
// https://gist.github.com/SizableShrimp/66b22f1b24c255e1491c8d98d3f11f83
// v--------------------------------------------------------------------v
configurations {
@ -131,14 +131,18 @@ minecraft.runs.all {
dependencies {
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
jarJar(group: 'com.dreizak', name: 'miniball', version: "1.0.3") {
jarJar.ranged(it, "[1.0,2.0)")
jarJar('org.joml:joml:1.10.5') {
jarJar.ranged(it, '[1.10.0,1.11.0)')
}
library "com.dreizak:miniball:1.0.3"
library 'org.joml:joml:1.10.5'
jarJar('com.dreizak:miniball:1.0.3') {
jarJar.ranged(it, '[1.0,2.0)')
}
library 'com.dreizak:miniball:1.0.3'
// switch to implementation for debugging
compileOnly fg.deobf("maven.modrinth:starlight-forge:1.0.2+1.18.2")
compileOnly fg.deobf("maven.modrinth:rubidium:0.5.3a")
compileOnly fg.deobf("maven.modrinth:oculus:1.18.2-1.2.5a")

View file

@ -1,6 +1,6 @@
package com.jozufozu.flywheel.api.instance;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
import org.joml.FrustumIntersection;
import net.minecraft.core.BlockPos;

View file

@ -1,6 +1,8 @@
package com.jozufozu.flywheel.backend.gl.shader;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL20.glDeleteProgram;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glUniform1i;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlObject;

View file

@ -7,6 +7,8 @@ import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.Backend;
@ -16,7 +18,6 @@ import com.jozufozu.flywheel.backend.instancing.ratelimit.NonLimiter;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.light.LightUpdater;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
import net.minecraft.core.BlockPos;

View file

@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.instancing;
import java.util.List;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.instancing.effect.Effect;
import com.jozufozu.flywheel.config.FlwCommands;
import com.jozufozu.flywheel.config.FlwConfig;

View file

@ -3,6 +3,8 @@ package com.jozufozu.flywheel.backend.instancing.blockentity;
import java.util.ArrayList;
import java.util.List;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancedPart;
@ -10,7 +12,6 @@ import com.jozufozu.flywheel.api.instancer.InstancerManager;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.util.box.GridAlignedBB;
import com.jozufozu.flywheel.util.box.ImmutableBox;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntity;

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.backend.instancing.compile;
import static org.lwjgl.opengl.GL11.GL_TRUE;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_TRUE;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glLinkProgram;

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.backend.instancing.entity;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.api.instancer.InstancerManager;
@ -8,7 +10,6 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceM
import com.jozufozu.flywheel.light.LightListener;
import com.jozufozu.flywheel.light.TickingLightListener;
import com.jozufozu.flywheel.util.box.GridAlignedBB;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
import com.mojang.math.Vector3f;
import net.minecraft.core.BlockPos;

View file

@ -1,7 +1,22 @@
package com.jozufozu.flywheel.backend.instancing.indirect;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.nglDeleteBuffers;
import static org.lwjgl.opengl.GL30.GL_MAP_FLUSH_EXPLICIT_BIT;
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
import static org.lwjgl.opengl.GL40.GL_DRAW_INDIRECT_BUFFER;
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BUFFER;
import static org.lwjgl.opengl.GL44.GL_DYNAMIC_STORAGE_BIT;
import static org.lwjgl.opengl.GL44.GL_MAP_PERSISTENT_BIT;
import static org.lwjgl.opengl.GL44.nglBindBuffersRange;
import static org.lwjgl.opengl.GL45.glCopyNamedBufferSubData;
import static org.lwjgl.opengl.GL45.glCreateBuffers;
import static org.lwjgl.opengl.GL46.*;
import static org.lwjgl.opengl.GL45.glFlushMappedNamedBufferRange;
import static org.lwjgl.opengl.GL45.glNamedBufferStorage;
import static org.lwjgl.opengl.GL45.nglCreateBuffers;
import static org.lwjgl.opengl.GL45.nglMapNamedBufferRange;
import static org.lwjgl.opengl.GL45.nglNamedBufferSubData;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.system.Pointer;

View file

@ -1,15 +1,15 @@
package com.jozufozu.flywheel.backend.instancing.indirect;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glDeleteVertexArrays;
import static org.lwjgl.opengl.GL42.GL_COMMAND_BARRIER_BIT;
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BARRIER_BIT;
import static org.lwjgl.opengl.GL46.glBindVertexArray;
import static org.lwjgl.opengl.GL46.glCreateVertexArrays;
import static org.lwjgl.opengl.GL46.glDeleteVertexArrays;
import static org.lwjgl.opengl.GL46.glDispatchCompute;
import static org.lwjgl.opengl.GL46.glEnableVertexArrayAttrib;
import static org.lwjgl.opengl.GL46.glVertexArrayElementBuffer;
import static org.lwjgl.opengl.GL46.glVertexArrayVertexBuffer;
import static org.lwjgl.opengl.GL43.glDispatchCompute;
import static org.lwjgl.opengl.GL45.glCreateVertexArrays;
import static org.lwjgl.opengl.GL45.glEnableVertexArrayAttrib;
import static org.lwjgl.opengl.GL45.glVertexArrayElementBuffer;
import static org.lwjgl.opengl.GL45.glVertexArrayVertexBuffer;
import com.jozufozu.flywheel.api.RenderStage;
import com.jozufozu.flywheel.api.instancer.InstancedPart;

View file

@ -16,9 +16,9 @@ import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.TaskExecutor;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.core.context.SimpleContext;
import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.util.FlwUtil;
import com.jozufozu.flywheel.core.context.SimpleContext;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Camera;

View file

@ -1,9 +1,9 @@
package com.jozufozu.flywheel.core;
import org.jetbrains.annotations.NotNull;
import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.util.MatrixUtil;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
@ -23,7 +23,7 @@ public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack
}
public static FrustumIntersection createCuller(Matrix4f viewProjection, float camX, float camY, float camZ) {
com.jozufozu.flywheel.util.joml.Matrix4f proj = MatrixUtil.toJoml(viewProjection);
org.joml.Matrix4f proj = MatrixUtil.toJoml(viewProjection);
proj.translate(camX, camY, camZ);

View file

@ -2,6 +2,9 @@ package com.jozufozu.flywheel.core.hardcoded;
import java.util.List;
import org.joml.Vector4f;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
import com.jozufozu.flywheel.api.vertex.ReusableVertexList;
import com.jozufozu.flywheel.backend.memory.MemoryBlock;
@ -9,8 +12,6 @@ import com.jozufozu.flywheel.core.model.Mesh;
import com.jozufozu.flywheel.core.model.ModelUtil;
import com.jozufozu.flywheel.core.vertex.Formats;
import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex;
import com.jozufozu.flywheel.util.joml.Vector4f;
import com.jozufozu.flywheel.util.joml.Vector4fc;
public class ModelPart implements Mesh {
private final int vertexCount;

View file

@ -1,10 +1,11 @@
package com.jozufozu.flywheel.core.model;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.instancing.instancing.ElementBuffer;
import com.jozufozu.flywheel.core.QuadConverter;
import com.jozufozu.flywheel.util.joml.Vector4fc;
/**
* A holder for arbitrary vertex data that can be written to memory or a vertex list.

View file

@ -4,6 +4,7 @@ import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector4f;
import org.lwjgl.system.MemoryUtil;
import com.dreizak.miniball.highdim.Miniball;
@ -17,7 +18,6 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.memory.MemoryBlock;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.vertex.Formats;
import com.jozufozu.flywheel.util.joml.Vector4f;
import com.mojang.blaze3d.vertex.BufferBuilder.DrawState;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.datafixers.util.Pair;

View file

@ -1,11 +1,12 @@
package com.jozufozu.flywheel.core.model;
import org.joml.Vector4f;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
import com.jozufozu.flywheel.api.vertex.ReusableVertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.memory.MemoryBlock;
import com.jozufozu.flywheel.util.joml.Vector4f;
import com.jozufozu.flywheel.util.joml.Vector4fc;
public class SimpleMesh implements Mesh {
private final VertexType vertexType;

View file

@ -1,6 +1,10 @@
package com.jozufozu.flywheel.core.source;
import java.util.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import com.google.common.collect.ImmutableList;

View file

@ -6,10 +6,10 @@ import java.util.Set;
import java.util.WeakHashMap;
import java.util.stream.Stream;
import org.joml.Math;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.util.joml.Math;
import com.jozufozu.flywheel.util.joml.Matrix4f;
import com.mojang.blaze3d.vertex.PoseStack;
public class FlwUtil {

View file

@ -63,7 +63,7 @@ public class MatrixUtil {
buf.putFloat(m.flywheel$m22());
}
public static void store(Matrix4f matrix, com.jozufozu.flywheel.util.joml.Matrix4f jomlMatrix) {
public static void store(Matrix4f matrix, org.joml.Matrix4f jomlMatrix) {
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
jomlMatrix.set(
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m30(),
@ -73,9 +73,9 @@ public class MatrixUtil {
);
}
public static com.jozufozu.flywheel.util.joml.Matrix4f toJoml(Matrix4f matrix) {
public static org.joml.Matrix4f toJoml(Matrix4f matrix) {
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
return new com.jozufozu.flywheel.util.joml.Matrix4f(
return new org.joml.Matrix4f(
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m30(),
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m31(),
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22(), m.flywheel$m32(),
@ -96,7 +96,7 @@ public class MatrixUtil {
MemoryUtil.memPutFloat(ptr + 32, m.flywheel$m22());
}
public static void store(Matrix3f matrix, com.jozufozu.flywheel.util.joml.Matrix3f jomlMatrix) {
public static void store(Matrix3f matrix, org.joml.Matrix3f jomlMatrix) {
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
jomlMatrix.set(
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(),
@ -105,9 +105,9 @@ public class MatrixUtil {
);
}
public static com.jozufozu.flywheel.util.joml.Matrix3f toJoml(Matrix3f matrix) {
public static org.joml.Matrix3f toJoml(Matrix3f matrix) {
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
return new com.jozufozu.flywheel.util.joml.Matrix3f(
return new org.joml.Matrix3f(
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(),
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(),
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22()

View file

@ -1,543 +0,0 @@
/*
* 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.util.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;
/**
* Represents a 3D rotation of a given radians about an axis represented as an
* unit 3D vector.
* <p>
* This class uses single-precision components.
*
* @author Kai Burjack
*/
public class AxisAngle4f implements Externalizable, Cloneable {
private static final long serialVersionUID = 1L;
/**
* The angle in radians.
*/
public float angle;
/**
* The x-component of the rotation axis.
*/
public float x;
/**
* The y-component of the rotation axis.
*/
public float y;
/**
* The z-component of the rotation axis.
*/
public float z;
/**
* Create a new {@link AxisAngle4f} with zero rotation about <code>(0, 0, 1)</code>.
*/
public AxisAngle4f() {
z = 1.0f;
}
/**
* Create a new {@link AxisAngle4f} with the same values of <code>a</code>.
*
* @param a
* the AngleAxis4f to copy the values from
*/
public AxisAngle4f(AxisAngle4f a) {
x = a.x;
y = a.y;
z = a.z;
angle = (float) ((a.angle < 0.0 ? Math.PI + Math.PI + a.angle % (Math.PI + Math.PI) : a.angle) % (Math.PI + Math.PI));
}
/**
* Create a new {@link AxisAngle4f} from the given {@link Quaternionfc}.
* <p>
* Reference: <a href=
* "http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/"
* >http://www.euclideanspace.com</a>
*
* @param q
* the quaternion from which to create the new AngleAxis4f
*/
public AxisAngle4f(Quaternionfc q) {
float acos = Math.safeAcos(q.w());
float invSqrt = Math.invsqrt(1.0f - q.w() * q.w());
if (Float.isInfinite(invSqrt)) {
this.x = 0.0f;
this.y = 0.0f;
this.z = 1.0f;
} else {
this.x = q.x() * invSqrt;
this.y = q.y() * invSqrt;
this.z = q.z() * invSqrt;
}
this.angle = acos + acos;
}
/**
* Create a new {@link AxisAngle4f} with the given values.
*
* @param angle
* the angle in radians
* @param x
* the x-coordinate of the rotation axis
* @param y
* the y-coordinate of the rotation axis
* @param z
* the z-coordinate of the rotation axis
*/
public AxisAngle4f(float angle, float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
this.angle = (float) ((angle < 0.0 ? Math.PI + Math.PI + angle % (Math.PI + Math.PI) : angle) % (Math.PI + Math.PI));
}
/**
* Create a new {@link AxisAngle4f} with the given values.
*
* @param angle the angle in radians
* @param v the rotation axis as a {@link Vector3f}
*/
public AxisAngle4f(float angle, Vector3fc v) {
this(angle, v.x(), v.y(), v.z());
}
/**
* Set this {@link AxisAngle4f} to the values of <code>a</code>.
*
* @param a
* the AngleAxis4f to copy the values from
* @return this
*/
public AxisAngle4f set(AxisAngle4f a) {
x = a.x;
y = a.y;
z = a.z;
angle = a.angle;
angle = (float) ((angle < 0.0 ? Math.PI + Math.PI + angle % (Math.PI + Math.PI) : angle) % (Math.PI + Math.PI));
return this;
}
/**
* Set this {@link AxisAngle4f} to the given values.
*
* @param angle
* the angle in radians
* @param x
* the x-coordinate of the rotation axis
* @param y
* the y-coordinate of the rotation axis
* @param z
* the z-coordinate of the rotation axis
* @return this
*/
public AxisAngle4f set(float angle, float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
this.angle = (float) ((angle < 0.0 ? Math.PI + Math.PI + angle % (Math.PI + Math.PI) : angle) % (Math.PI + Math.PI));
return this;
}
/**
* Set this {@link AxisAngle4f} to the given values.
*
* @param angle
* the angle in radians
* @param v
* the rotation axis as a {@link Vector3f}
* @return this
*/
public AxisAngle4f set(float angle, Vector3fc v) {
return set(angle, v.x(), v.y(), v.z());
}
/**
* Set this {@link AxisAngle4f} to be equivalent to the given
* {@link Quaternionfc}.
*
* @param q
* the quaternion to set this AngleAxis4f from
* @return this
*/
public AxisAngle4f set(Quaternionfc q) {
float acos = Math.safeAcos(q.w());
float invSqrt = Math.invsqrt(1.0f - q.w() * q.w());
if (Float.isInfinite(invSqrt)) {
this.x = 0.0f;
this.y = 0.0f;
this.z = 1.0f;
} else {
this.x = q.x() * invSqrt;
this.y = q.y() * invSqrt;
this.z = q.z() * invSqrt;
}
this.angle = acos + acos;
return this;
}
/**
* Set this {@link AxisAngle4f} to be equivalent to the rotation
* of the given {@link Matrix3fc}.
* <p>
* Reference: <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/">http://www.euclideanspace.com</a>
*
* @param m
* the Matrix3fc to set this AngleAxis4f from
* @return this
*/
public AxisAngle4f set(Matrix3fc m) {
float nm00 = m.m00(), nm01 = m.m01(), nm02 = m.m02();
float nm10 = m.m10(), nm11 = m.m11(), nm12 = m.m12();
float nm20 = m.m20(), nm21 = m.m21(), nm22 = m.m22();
float lenX = Math.invsqrt(m.m00() * m.m00() + m.m01() * m.m01() + m.m02() * m.m02());
float lenY = Math.invsqrt(m.m10() * m.m10() + m.m11() * m.m11() + m.m12() * m.m12());
float lenZ = Math.invsqrt(m.m20() * m.m20() + m.m21() * m.m21() + m.m22() * m.m22());
nm00 *= lenX; nm01 *= lenX; nm02 *= lenX;
nm10 *= lenY; nm11 *= lenY; nm12 *= lenY;
nm20 *= lenZ; nm21 *= lenZ; nm22 *= lenZ;
float epsilon = 1E-4f, epsilon2 = 1E-3f;
if (Math.abs(nm10 - nm01) < epsilon && Math.abs(nm20 - nm02) < epsilon && Math.abs(nm21 - nm12) < epsilon) {
if (Math.abs(nm10 + nm01) < epsilon2 && Math.abs(nm20 + nm02) < epsilon2 && Math.abs(nm21 + nm12) < epsilon2
&& Math.abs(nm00 + nm11 + nm22 - 3) < epsilon2) {
x = 0;
y = 0;
z = 1;
angle = 0;
return this;
}
angle = Math.PI_f;
float xx = (nm00 + 1) / 2;
float yy = (nm11 + 1) / 2;
float zz = (nm22 + 1) / 2;
float xy = (nm10 + nm01) / 4;
float xz = (nm20 + nm02) / 4;
float yz = (nm21 + nm12) / 4;
if ((xx > yy) && (xx > zz)) {
x = Math.sqrt(xx);
y = xy / x;
z = xz / x;
} else if (yy > zz) {
y = Math.sqrt(yy);
x = xy / y;
z = yz / y;
} else {
z = Math.sqrt(zz);
x = xz / z;
y = yz / z;
}
return this;
}
float s = Math.sqrt((nm12 - nm21) * (nm12 - nm21) + (nm20 - nm02) * (nm20 - nm02) + (nm01 - nm10) * (nm01 - nm10));
angle = Math.safeAcos((nm00 + nm11 + nm22 - 1) / 2);
x = (nm12 - nm21) / s;
y = (nm20 - nm02) / s;
z = (nm01 - nm10) / s;
return this;
}
/**
* Set this {@link AxisAngle4f} to be equivalent to the rotational component
* of the given {@link Matrix4fc}.
* <p>
* Reference: <a href="http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/">http://www.euclideanspace.com</a>
*
* @param m
* the Matrix4fc to set this AngleAxis4f from
* @return this
*/
public AxisAngle4f set(Matrix4fc m) {
float nm00 = m.m00(), nm01 = m.m01(), nm02 = m.m02();
float nm10 = m.m10(), nm11 = m.m11(), nm12 = m.m12();
float nm20 = m.m20(), nm21 = m.m21(), nm22 = m.m22();
float lenX = Math.invsqrt(m.m00() * m.m00() + m.m01() * m.m01() + m.m02() * m.m02());
float lenY = Math.invsqrt(m.m10() * m.m10() + m.m11() * m.m11() + m.m12() * m.m12());
float lenZ = Math.invsqrt(m.m20() * m.m20() + m.m21() * m.m21() + m.m22() * m.m22());
nm00 *= lenX; nm01 *= lenX; nm02 *= lenX;
nm10 *= lenY; nm11 *= lenY; nm12 *= lenY;
nm20 *= lenZ; nm21 *= lenZ; nm22 *= lenZ;
float epsilon = 1E-4f, epsilon2 = 1E-3f;
if (Math.abs(nm10 - nm01) < epsilon && Math.abs(nm20 - nm02) < epsilon && Math.abs(nm21 - nm12) < epsilon) {
if (Math.abs(nm10 + nm01) < epsilon2 && Math.abs(nm20 + nm02) < epsilon2 && Math.abs(nm21 + nm12) < epsilon2
&& Math.abs(nm00 + nm11 + nm22 - 3) < epsilon2) {
x = 0;
y = 0;
z = 1;
angle = 0;
return this;
}
angle = Math.PI_f;
float xx = (nm00 + 1) / 2;
float yy = (nm11 + 1) / 2;
float zz = (nm22 + 1) / 2;
float xy = (nm10 + nm01) / 4;
float xz = (nm20 + nm02) / 4;
float yz = (nm21 + nm12) / 4;
if ((xx > yy) && (xx > zz)) {
x = Math.sqrt(xx);
y = xy / x;
z = xz / x;
} else if (yy > zz) {
y = Math.sqrt(yy);
x = xy / y;
z = yz / y;
} else {
z = Math.sqrt(zz);
x = xz / z;
y = yz / z;
}
return this;
}
float s = Math.sqrt((nm12 - nm21) * (nm12 - nm21) + (nm20 - nm02) * (nm20 - nm02) + (nm01 - nm10) * (nm01 - nm10));
angle = Math.safeAcos((nm00 + nm11 + nm22 - 1) / 2);
x = (nm12 - nm21) / s;
y = (nm20 - nm02) / s;
z = (nm01 - nm10) / s;
return this;
}
/**
* Set the given {@link Quaternionf} to be equivalent to this {@link AxisAngle4f} rotation.
*
* @see Quaternionf#set(AxisAngle4f)
*
* @param q
* the quaternion to set
* @return q
*/
public Quaternionf get(Quaternionf q) {
return q.set(this);
}
/**
* Set the given {@link Matrix4f} to a rotation transformation equivalent to this {@link AxisAngle4f}.
*
* @see Matrix4f#set(AxisAngle4f)
*
* @param m
* the matrix to set
* @return m
*/
public Matrix4f get(Matrix4f m) {
return m.set(this);
}
/**
* Set the given {@link Matrix3f} to a rotation transformation equivalent to this {@link AxisAngle4f}.
*
* @see Matrix3f#set(AxisAngle4f)
*
* @param m
* the matrix to set
* @return m
*/
public Matrix3f get(Matrix3f m) {
return m.set(this);
}
/**
* Set the given {@link AxisAngle4f} to this {@link AxisAngle4f}.
*
* @param dest
* will hold the result
* @return dest
*/
public AxisAngle4f get(AxisAngle4f dest) {
return dest.set(this);
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeFloat(angle);
out.writeFloat(x);
out.writeFloat(y);
out.writeFloat(z);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
angle = in.readFloat();
x = in.readFloat();
y = in.readFloat();
z = in.readFloat();
}
/**
* Normalize the axis vector.
*
* @return this
*/
public AxisAngle4f normalize() {
float invLength = Math.invsqrt(x * x + y * y + z * z);
x *= invLength;
y *= invLength;
z *= invLength;
return this;
}
/**
* Increase the rotation angle by the given amount.
* <p>
* This method also takes care of wrapping around.
*
* @param ang
* the angle increase
* @return this
*/
public AxisAngle4f rotate(float ang) {
angle += ang;
angle = (float) ((angle < 0.0 ? Math.PI + Math.PI + angle % (Math.PI + Math.PI) : angle) % (Math.PI + Math.PI));
return this;
}
/**
* Transform the given vector by the rotation transformation described by this {@link AxisAngle4f}.
*
* @param v
* the vector to transform
* @return v
*/
public Vector3f transform(Vector3f v) {
return transform(v, v);
}
/**
* Transform the given vector by the rotation transformation described by this {@link AxisAngle4f}
* and store the result in <code>dest</code>.
*
* @param v
* the vector to transform
* @param dest
* will hold the result
* @return dest
*/
public Vector3f transform(Vector3fc v, Vector3f dest) {
double sin = Math.sin(angle);
double cos = Math.cosFromSin(sin, angle);
float dot = x * v.x() + y * v.y() + z * v.z();
dest.set((float) (v.x() * cos + sin * (y * v.z() - z * v.y()) + (1.0 - cos) * dot * x),
(float) (v.y() * cos + sin * (z * v.x() - x * v.z()) + (1.0 - cos) * dot * y),
(float) (v.z() * cos + sin * (x * v.y() - y * v.x()) + (1.0 - cos) * dot * z));
return dest;
}
/**
* Transform the given vector by the rotation transformation described by this {@link AxisAngle4f}.
*
* @param v
* the vector to transform
* @return v
*/
public Vector4f transform(Vector4f v) {
return transform(v, v);
}
/**
* Transform the given vector by the rotation transformation described by this {@link AxisAngle4f}
* and store the result in <code>dest</code>.
*
* @param v
* the vector to transform
* @param dest
* will hold the result
* @return dest
*/
public Vector4f transform(Vector4fc v, Vector4f dest) {
double sin = Math.sin(angle);
double cos = Math.cosFromSin(sin, angle);
float dot = x * v.x() + y * v.y() + z * v.z();
dest.set((float) (v.x() * cos + sin * (y * v.z() - z * v.y()) + (1.0 - cos) * dot * x),
(float) (v.y() * cos + sin * (z * v.x() - x * v.z()) + (1.0 - cos) * dot * y),
(float) (v.z() * cos + sin * (x * v.y() - y * v.x()) + (1.0 - cos) * dot * z),
dest.w);
return dest;
}
/**
* Return a string representation of this {@link AxisAngle4f}.
* <p>
* This method creates a new {@link DecimalFormat} on every invocation with the format string "<code> 0.000E0;-</code>".
*
* @return the string representation
*/
public String toString() {
return Runtime.formatNumbers(toString(Options.NUMBER_FORMAT));
}
/**
* Return a string representation of this {@link AxisAngle4f} by formatting the 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(angle, formatter) + ")";
}
public int hashCode() {
final int prime = 31;
int result = 1;
float nangle = (float) ((angle < 0.0 ? Math.PI + Math.PI + angle % (Math.PI + Math.PI) : angle) % (Math.PI + Math.PI));
result = prime * result + Float.floatToIntBits(nangle);
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;
AxisAngle4f other = (AxisAngle4f) obj;
float nangle = (float) ((angle < 0.0 ? Math.PI + Math.PI + angle % (Math.PI + Math.PI) : angle) % (Math.PI + Math.PI));
float nangleOther = (float) ((other.angle < 0.0 ? Math.PI + Math.PI + other.angle % (Math.PI + Math.PI) : other.angle) % (Math.PI + Math.PI));
if (Float.floatToIntBits(nangle) != Float.floatToIntBits(nangleOther))
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 Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

View file

@ -1,36 +0,0 @@
/*
* 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.util.joml;
/**
* Exception thrown when using an invalid JOML runtime configuration.
*
* @author Kai Burjack
*/
public class ConfigurationException extends RuntimeException {
private static final long serialVersionUID = -7832356906364070687L;
public ConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}

View file

@ -1,992 +0,0 @@
/*
* 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.util.joml;
import java.nio.ByteBuffer;
import org.lwjgl.system.MemoryUtil;
/**
* Efficiently performs frustum intersection tests by caching the frustum planes of an arbitrary transformation {@link Matrix4fc matrix}.
* <p>
* This class is preferred over the frustum intersection methods in {@link Matrix4fc} when many objects need to be culled by the same static frustum.
*
* @author Kai Burjack
*/
public class FrustumIntersection {
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads identifying the plane with equation <code>x=-1</code> when using the identity frustum.
*/
public static final int PLANE_NX = 0;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads identifying the plane with equation <code>x=1</code> when using the identity frustum.
*/
public static final int PLANE_PX = 1;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads identifying the plane with equation <code>y=-1</code> when using the identity frustum.
*/
public static final int PLANE_NY= 2;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads identifying the plane with equation <code>y=1</code> when using the identity frustum.
*/
public static final int PLANE_PY = 3;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads identifying the plane with equation <code>z=-1</code> when using the identity frustum.
*/
public static final int PLANE_NZ = 4;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads identifying the plane with equation <code>z=1</code> when using the identity frustum.
*/
public static final int PLANE_PZ = 5;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads indicating that the axis-aligned box intersects the frustum.
*/
public static final int INTERSECT = -1;
/**
* Return value of {@link #intersectAab(float, float, float, float, float, float) intersectAab()}
* and its different overloads indicating that the axis-aligned box is fully inside of the frustum.
*/
public static final int INSIDE = -2;
/**
* Return value of {@link #intersectSphere(Vector3fc, float)} or {@link #intersectSphere(float, float, float, float)}
* indicating that the sphere is completely outside of the frustum.
*/
public static final int OUTSIDE = -3;
/**
* The value in a bitmask for
* {@link #intersectAab(float, float, float, float, float, float, int) intersectAab()}
* that identifies the plane with equation <code>x=-1</code> when using the identity frustum.
*/
public static final int PLANE_MASK_NX = 1<<PLANE_NX;
/**
* The value in a bitmask for
* {@link #intersectAab(float, float, float, float, float, float, int) intersectAab()}
* that identifies the plane with equation <code>x=1</code> when using the identity frustum.
*/
public static final int PLANE_MASK_PX = 1<<PLANE_PX;
/**
* The value in a bitmask for
* {@link #intersectAab(float, float, float, float, float, float, int) intersectAab()}
* that identifies the plane with equation <code>y=-1</code> when using the identity frustum.
*/
public static final int PLANE_MASK_NY = 1<<PLANE_NY;
/**
* The value in a bitmask for
* {@link #intersectAab(float, float, float, float, float, float, int) intersectAab()}
* that identifies the plane with equation <code>y=1</code> when using the identity frustum.
*/
public static final int PLANE_MASK_PY = 1<<PLANE_PY;
/**
* The value in a bitmask for
* {@link #intersectAab(float, float, float, float, float, float, int) intersectAab()}
* that identifies the plane with equation <code>z=-1</code> when using the identity frustum.
*/
public static final int PLANE_MASK_NZ = 1<<PLANE_NZ;
/**
* The value in a bitmask for
* {@link #intersectAab(float, float, float, float, float, float, int) intersectAab()}
* that identifies the plane with equation <code>z=1</code> when using the identity frustum.
*/
public static final int PLANE_MASK_PZ = 1<<PLANE_PZ;
private float nxX, nxY, nxZ, nxW;
private float pxX, pxY, pxZ, pxW;
private float nyX, nyY, nyZ, nyW;
private float pyX, pyY, pyZ, pyW;
private float nzX, nzY, nzZ, nzW;
private float pzX, pzY, pzZ, pzW;
private final Vector4f[] planes = new Vector4f[6];
{
for (int i = 0; i < 6; i++) {
planes[i] = new Vector4f();
}
}
/**
* Create a new {@link FrustumIntersection} with undefined frustum planes.
* <p>
* Before using any of the frustum culling methods, make sure to define the frustum planes using {@link #set(Matrix4fc)}.
*/
public FrustumIntersection() {
}
/**
* Create a new {@link FrustumIntersection} from the given {@link Matrix4fc matrix} by extracing the matrix's frustum planes.
* <p>
* In order to update the compute frustum planes later on, call {@link #set(Matrix4fc)}.
*
* @see #set(Matrix4fc)
*
* @param m
* the {@link Matrix4fc} to create the frustum culler from
*/
public FrustumIntersection(Matrix4fc m) {
set(m, true);
}
/**
* Create a new {@link FrustumIntersection} from the given {@link Matrix4fc matrix} by extracing the matrix's frustum planes.
* <p>
* In order to update the compute frustum planes later on, call {@link #set(Matrix4fc)}.
*
* @see #set(Matrix4fc)
*
* @param m
* the {@link Matrix4fc} to create the frustum culler from
* @param allowTestSpheres
* whether the methods {@link #testSphere(Vector3fc, float)}, {@link #testSphere(float, float, float, float)},
* {@link #intersectSphere(Vector3fc, float)} or {@link #intersectSphere(float, float, float, float)} will used.
* If no spheres need to be tested, then <code>false</code> should be used
*/
public FrustumIntersection(Matrix4fc m, boolean allowTestSpheres) {
set(m, allowTestSpheres);
}
/**
* Update the stored frustum planes of <code>this</code> {@link FrustumIntersection} with the given {@link Matrix4fc matrix}.
* <p>
* Reference: <a href="http://gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf">
* Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix</a>
*
* @param m
* the {@link Matrix4fc matrix} to update <code>this</code> frustum culler's frustum planes from
* @return this
*/
public FrustumIntersection set(Matrix4fc m) {
return set(m, true);
}
/**
* Update the stored frustum planes of <code>this</code> {@link FrustumIntersection} with the given {@link Matrix4fc matrix} and
* allow to optimize the frustum plane extraction in the case when no intersection test is needed for spheres.
* <p>
* Reference: <a href="http://gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf">
* Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix</a>
*
* @param m
* the {@link Matrix4fc matrix} to update <code>this</code> frustum culler's frustum planes from
* @param allowTestSpheres
* whether the methods {@link #testSphere(Vector3fc, float)}, {@link #testSphere(float, float, float, float)},
* {@link #intersectSphere(Vector3fc, float)} or {@link #intersectSphere(float, float, float, float)} will be used.
* If no spheres need to be tested, then <code>false</code> should be used
* @return this
*/
public FrustumIntersection set(Matrix4fc m, boolean allowTestSpheres) {
float invl;
nxX = m.m03() + m.m00(); nxY = m.m13() + m.m10(); nxZ = m.m23() + m.m20(); nxW = m.m33() + m.m30();
if (allowTestSpheres) {
invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ);
nxX *= invl; nxY *= invl; nxZ *= invl; nxW *= invl;
}
planes[0].set(nxX, nxY, nxZ, nxW);
pxX = m.m03() - m.m00(); pxY = m.m13() - m.m10(); pxZ = m.m23() - m.m20(); pxW = m.m33() - m.m30();
if (allowTestSpheres) {
invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ);
pxX *= invl; pxY *= invl; pxZ *= invl; pxW *= invl;
}
planes[1].set(pxX, pxY, pxZ, pxW);
nyX = m.m03() + m.m01(); nyY = m.m13() + m.m11(); nyZ = m.m23() + m.m21(); nyW = m.m33() + m.m31();
if (allowTestSpheres) {
invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ);
nyX *= invl; nyY *= invl; nyZ *= invl; nyW *= invl;
}
planes[2].set(nyX, nyY, nyZ, nyW);
pyX = m.m03() - m.m01(); pyY = m.m13() - m.m11(); pyZ = m.m23() - m.m21(); pyW = m.m33() - m.m31();
if (allowTestSpheres) {
invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ);
pyX *= invl; pyY *= invl; pyZ *= invl; pyW *= invl;
}
planes[3].set(pyX, pyY, pyZ, pyW);
nzX = m.m03() + m.m02(); nzY = m.m13() + m.m12(); nzZ = m.m23() + m.m22(); nzW = m.m33() + m.m32();
if (allowTestSpheres) {
invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ);
nzX *= invl; nzY *= invl; nzZ *= invl; nzW *= invl;
}
planes[4].set(nzX, nzY, nzZ, nzW);
pzX = m.m03() - m.m02(); pzY = m.m13() - m.m12(); pzZ = m.m23() - m.m22(); pzW = m.m33() - m.m32();
if (allowTestSpheres) {
invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ);
pzX *= invl; pzY *= invl; pzZ *= invl; pzW *= invl;
}
planes[5].set(pzX, pzY, pzZ, pzW);
return this;
}
/**
* Test whether the given point is within the frustum defined by <code>this</code> frustum culler.
*
* @param point
* the point to test
* @return <code>true</code> if the given point is inside the frustum; <code>false</code> otherwise
*/
public boolean testPoint(Vector3fc point) {
return testPoint(point.x(), point.y(), point.z());
}
/**
* Test whether the given point <code>(x, y, z)</code> is within the frustum defined by <code>this</code> frustum culler.
*
* @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 <code>true</code> if the given point is inside the frustum; <code>false</code> otherwise
*/
public boolean testPoint(float x, float y, float z) {
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;
}
/**
* Test whether the given sphere is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns <code>true</code> for spheres that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @param center
* the sphere's center
* @param radius
* the sphere's radius
* @return <code>true</code> if the given sphere is partly or completely inside the frustum;
* <code>false</code> otherwise
*/
public boolean testSphere(Vector3fc center, float radius) {
return testSphere(center.x(), center.y(), center.z(), radius);
}
/**
* Test whether the given sphere is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns <code>true</code> for spheres that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @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 <code>true</code> if the given sphere is partly or completely inside the frustum;
* <code>false</code> otherwise
*/
public boolean testSphere(float x, float y, float z, float r) {
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;
}
/**
* Determine whether the given sphere is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for spheres that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @param center
* the sphere's center
* @param radius
* the sphere's radius
* @return {@link #INSIDE} if the given sphere is completely inside the frustum, or {@link #INTERSECT} if the sphere intersects
* the frustum, or {@link #OUTSIDE} if the sphere is outside of the frustum
*/
public int intersectSphere(Vector3fc center, float radius) {
return intersectSphere(center.x(), center.y(), center.z(), radius);
}
/**
* Determine whether the given sphere is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for spheres that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @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 {@link #INSIDE} if the given sphere is completely inside the frustum, or {@link #INTERSECT} if the sphere intersects
* the frustum, or {@link #OUTSIDE} if the sphere is outside of the frustum
*/
public int intersectSphere(float x, float y, float z, float r) {
boolean inside = true;
float dist;
dist = nxX * x + nxY * y + nxZ * z + nxW;
if (dist >= -r) {
inside &= dist >= r;
dist = pxX * x + pxY * y + pxZ * z + pxW;
if (dist >= -r) {
inside &= dist >= r;
dist = nyX * x + nyY * y + nyZ * z + nyW;
if (dist >= -r) {
inside &= dist >= r;
dist = pyX * x + pyY * y + pyZ * z + pyW;
if (dist >= -r) {
inside &= dist >= r;
dist = nzX * x + nzY * y + nzZ * z + nzW;
if (dist >= -r) {
inside &= dist >= r;
dist = pzX * x + pzY * y + pzZ * z + pzW;
if (dist >= -r) {
inside &= dist >= r;
return inside ? INSIDE : INTERSECT;
}
}
}
}
}
}
return OUTSIDE;
}
/**
* Test whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* The box is specified via its <code>min</code> and <code>max</code> corner coordinates.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns <code>true</code> for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @param min
* the minimum corner coordinates of the axis-aligned box
* @param max
* the maximum corner coordinates of the axis-aligned box
* @return <code>true</code> if the axis-aligned box is completely or partly inside of the frustum; <code>false</code> otherwise
*/
public boolean testAab(Vector3fc min, Vector3fc max) {
return testAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z());
}
/**
* Test whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* The box is specified via its min and max corner coordinates.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns <code>true</code> for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
* <p>
* Reference: <a href="http://old.cescg.org/CESCG-2002/DSykoraJJelinek/">Efficient View Frustum Culling</a>
*
* @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 <code>true</code> if the axis-aligned box is completely or partly inside of the frustum; <code>false</code> otherwise
*/
public boolean testAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
/*
* 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;
}
/**
* Test whether the given XY-plane (at <code>Z = 0</code>) is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* The plane is specified via its min and max corner coordinates.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns <code>true</code> for planes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
* <p>
* Reference: <a href="http://old.cescg.org/CESCG-2002/DSykoraJJelinek/">Efficient View Frustum Culling</a>
*
* @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 <code>true</code> if the XY-plane is completely or partly inside of the frustum; <code>false</code> otherwise
*/
public boolean testPlaneXY(float minX, float minY, float maxX, float maxY) {
/*
* 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 &&
nzX * (nzX < 0 ? minX : maxX) + nzY * (nzY < 0 ? minY : maxY) >= -nzW &&
pzX * (pzX < 0 ? minX : maxX) + pzY * (pzY < 0 ? minY : maxY) >= -pzW;
}
/**
* Test whether the given XZ-plane (at <code>Y = 0</code>) is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler.
* The plane is specified via its min and max corner coordinates.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns <code>true</code> for planes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
* <p>
* Reference: <a href="http://old.cescg.org/CESCG-2002/DSykoraJJelinek/">Efficient View Frustum Culling</a>
*
* @param minX
* the x-coordinate of the minimum corner
* @param minZ
* the z-coordinate of the minimum corner
* @param maxX
* the x-coordinate of the maximum corner
* @param maxZ
* the z-coordinate of the maximum corner
* @return <code>true</code> if the XZ-plane is completely or partly inside of the frustum; <code>false</code> otherwise
*/
public boolean testPlaneXZ(float minX, float minZ, float maxX, float maxZ) {
/*
* 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) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW &&
pxX * (pxX < 0 ? minX : maxX) + pxZ * (pxZ < 0 ? minZ : maxZ) >= -pxW &&
nyX * (nyX < 0 ? minX : maxX) + nyZ * (nyZ < 0 ? minZ : maxZ) >= -nyW &&
pyX * (pyX < 0 ? minX : maxX) + pyZ * (pyZ < 0 ? minZ : maxZ) >= -pyW &&
nzX * (nzX < 0 ? minX : maxX) + nzZ * (nzZ < 0 ? minZ : maxZ) >= -nzW &&
pzX * (pzX < 0 ? minX : maxX) + pzZ * (pzZ < 0 ? minZ : maxZ) >= -pzW;
}
/**
* Determine whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler
* and, if the box is not inside this frustum, return the index of the plane that culled it.
* The box is specified via its <code>min</code> and <code>max</code> corner coordinates.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @param min
* the minimum corner coordinates of the axis-aligned box
* @param max
* the maximum corner coordinates of the axis-aligned box
* @return the index of the first plane that culled the box, if the box does not intersect the frustum;
* or {@link #INTERSECT} if the box intersects the frustum, or {@link #INSIDE} if the box is fully inside of the frustum.
* The plane index is one of {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
*/
public int intersectAab(Vector3fc min, Vector3fc max) {
return intersectAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z());
}
/**
* Determine whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler
* and, if the box is not inside this frustum, return the index of the plane that culled it.
* The box is specified via its min and max corner coordinates.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
* <p>
* Reference: <a href="http://old.cescg.org/CESCG-2002/DSykoraJJelinek/">Efficient View Frustum Culling</a>
*
* @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 the index of the first plane that culled the box, if the box does not intersect the frustum,
* or {@link #INTERSECT} if the box intersects the frustum, or {@link #INSIDE} if the box is fully inside of the frustum.
* The plane index is one of {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
*/
public int intersectAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ) {
/*
* This is an implementation of the "2.4 Basic intersection test" of the mentioned site.
*
* In addition to the algorithm in the paper, this method also returns the index of the first plane that culled the box.
*/
int plane = PLANE_NX;
boolean inside = true;
if (nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -nxW) {
plane = PLANE_PX;
inside &= nxX * (nxX < 0 ? maxX : minX) + nxY * (nxY < 0 ? maxY : minY) + nxZ * (nxZ < 0 ? maxZ : minZ) >= -nxW;
if (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 (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 (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 (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 (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;
}
/**
* Compute the signed distance from the given axis-aligned box to the <code>plane</code>.
*
* @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
* @param plane
* one of
* {@link #PLANE_NX}, {@link #PLANE_PX},
* {@link #PLANE_NY}, {@link #PLANE_PY},
* {@link #PLANE_NZ} and {@link #PLANE_PZ}
* @return the signed distance of the axis-aligned box to the plane
*/
public float distanceToPlane(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int plane) {
return planes[plane].x * (planes[plane].x < 0 ? maxX : minX) + planes[plane].y * (planes[plane].y < 0 ? maxY : minY)
+ planes[plane].z * (planes[plane].z < 0 ? maxZ : minZ) + planes[plane].w;
}
/**
* Determine whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler
* and, if the box is not inside this frustum, return the index of the plane that culled it.
* The box is specified via its <code>min</code> and <code>max</code> corner coordinates.
* <p>
* This method differs from {@link #intersectAab(Vector3fc, Vector3fc)} in that
* it allows to mask-off planes that should not be calculated. For example, in order to only test a box against the
* left frustum plane, use a mask of {@link #PLANE_MASK_NX}. Or in order to test all planes <i>except</i> the left plane, use
* a mask of <code>(~0 ^ PLANE_MASK_NX)</code>.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @param min
* the minimum corner coordinates of the axis-aligned box
* @param max
* the maximum corner coordinates of the axis-aligned box
* @param mask
* contains as bitset all the planes that should be tested.
* This value can be any combination of
* {@link #PLANE_MASK_NX}, {@link #PLANE_MASK_PX},
* {@link #PLANE_MASK_NY}, {@link #PLANE_MASK_PY},
* {@link #PLANE_MASK_NZ} and {@link #PLANE_MASK_PZ}
* @return the index of the first plane that culled the box, if the box does not intersect the frustum,
* or {@link #INTERSECT} if the box intersects the frustum, or {@link #INSIDE} if the box is fully inside of the frustum.
* The plane index is one of {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
*/
public int intersectAab(Vector3fc min, Vector3fc max, int mask) {
return intersectAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), mask);
}
/**
* Determine whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler
* and, if the box is not inside this frustum, return the index of the plane that culled it.
* The box is specified via its min and max corner coordinates.
* <p>
* This method differs from {@link #intersectAab(float, float, float, float, float, float)} in that
* it allows to mask-off planes that should not be calculated. For example, in order to only test a box against the
* left frustum plane, use a mask of {@link #PLANE_MASK_NX}. Or in order to test all planes <i>except</i> the left plane, use
* a mask of <code>(~0 ^ PLANE_MASK_NX)</code>.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
* <p>
* Reference: <a href="http://old.cescg.org/CESCG-2002/DSykoraJJelinek/">Efficient View Frustum Culling</a>
*
* @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
* @param mask
* contains as bitset all the planes that should be tested.
* This value can be any combination of
* {@link #PLANE_MASK_NX}, {@link #PLANE_MASK_PX},
* {@link #PLANE_MASK_NY}, {@link #PLANE_MASK_PY},
* {@link #PLANE_MASK_NZ} and {@link #PLANE_MASK_PZ}
* @return the index of the first plane that culled the box, if the box does not intersect the frustum,
* or {@link #INTERSECT} if the box intersects the frustum, or {@link #INSIDE} if the box is fully inside of the frustum.
* The plane index is one of {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
*/
public int intersectAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int mask) {
/*
* This is an implementation of the first algorithm in "2.5 Plane masking and coherency" of the mentioned site.
*
* In addition to the algorithm in the paper, this method also returns the index of the first plane that culled the box.
*/
int plane = PLANE_NX;
boolean inside = true;
if ((mask & PLANE_MASK_NX) == 0 || nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -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;
}
/**
* Determine whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler
* and, if the box is not inside this frustum, return the index of the plane that culled it.
* The box is specified via its <code>min</code> and <code>max</code> corner coordinates.
* <p>
* This method differs from {@link #intersectAab(Vector3fc, Vector3fc)} in that
* it allows to mask-off planes that should not be calculated. For example, in order to only test a box against the
* left frustum plane, use a mask of {@link #PLANE_MASK_NX}. Or in order to test all planes <i>except</i> the left plane, use
* a mask of <code>(~0 ^ PLANE_MASK_NX)</code>.
* <p>
* In addition, the <code>startPlane</code> denotes the first frustum plane to test the box against. To use this effectively means to store the
* plane that previously culled an axis-aligned box (as returned by <code>intersectAab()</code>) and in the next frame use the return value
* as the argument to the <code>startPlane</code> parameter of this method. The assumption is that the plane that culled the object previously will also
* cull it now (temporal coherency) and the culling computation is likely reduced in that case.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
*
* @param min
* the minimum corner coordinates of the axis-aligned box
* @param max
* the maximum corner coordinates of the axis-aligned box
* @param mask
* contains as bitset all the planes that should be tested.
* This value can be any combination of
* {@link #PLANE_MASK_NX}, {@link #PLANE_MASK_PX},
* {@link #PLANE_MASK_NY}, {@link #PLANE_MASK_PY},
* {@link #PLANE_MASK_NZ} and {@link #PLANE_MASK_PZ}
* @param startPlane
* the first frustum plane to test the axis-aligned box against. It is one of
* {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
* @return the index of the first plane that culled the box, if the box does not intersect the frustum,
* or {@link #INTERSECT} if the box intersects the frustum, or {@link #INSIDE} if the box is fully inside of the frustum.
* The plane index is one of {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
*/
public int intersectAab(Vector3fc min, Vector3fc max, int mask, int startPlane) {
return intersectAab(min.x(), min.y(), min.z(), max.x(), max.y(), max.z(), mask, startPlane);
}
/**
* Determine whether the given axis-aligned box is partly or completely within or outside of the frustum defined by <code>this</code> frustum culler
* and, if the box is not inside this frustum, return the index of the plane that culled it.
* The box is specified via its min and max corner coordinates.
* <p>
* This method differs from {@link #intersectAab(float, float, float, float, float, float)} in that
* it allows to mask-off planes that should not be calculated. For example, in order to only test a box against the
* left frustum plane, use a mask of {@link #PLANE_MASK_NX}. Or in order to test all planes <i>except</i> the left plane, use
* a mask of <code>(~0 ^ PLANE_MASK_NX)</code>.
* <p>
* In addition, the <code>startPlane</code> denotes the first frustum plane to test the box against. To use this effectively means to store the
* plane that previously culled an axis-aligned box (as returned by <code>intersectAab()</code>) and in the next frame use the return value
* as the argument to the <code>startPlane</code> parameter of this method. The assumption is that the plane that culled the object previously will also
* cull it now (temporal coherency) and the culling computation is likely reduced in that case.
* <p>
* The algorithm implemented by this method is conservative. This means that in certain circumstances a <i>false positive</i>
* can occur, when the method returns {@link #INTERSECT} for boxes that do not intersect the frustum.
* See <a href="http://iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm">iquilezles.org</a> for an examination of this problem.
* <p>
* Reference: <a href="http://old.cescg.org/CESCG-2002/DSykoraJJelinek/">Efficient View Frustum Culling</a>
*
* @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
* @param mask
* contains as bitset all the planes that should be tested.
* This value can be any combination of
* {@link #PLANE_MASK_NX}, {@link #PLANE_MASK_PX},
* {@link #PLANE_MASK_NY}, {@link #PLANE_MASK_PY},
* {@link #PLANE_MASK_NZ} and {@link #PLANE_MASK_PZ}
* @param startPlane
* the first frustum plane to test the axis-aligned box against. It is one of
* {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
* @return the index of the first plane that culled the box, if the box does not intersect the frustum,
* or {@link #INTERSECT} if the box intersects the frustum, or {@link #INSIDE} if the box is fully inside of the frustum.
* The plane index is one of {@link #PLANE_NX}, {@link #PLANE_PX}, {@link #PLANE_NY}, {@link #PLANE_PY}, {@link #PLANE_NZ} and {@link #PLANE_PZ}
*/
public int intersectAab(float minX, float minY, float minZ, float maxX, float maxY, float maxZ, int mask, int startPlane) {
/*
* This is an implementation of the second algorithm in "2.5 Plane masking and coherency" of the mentioned site.
*
* In addition to the algorithm in the paper, this method also returns the index of the first plane that culled the box.
*/
int plane = startPlane;
boolean inside = true;
Vector4f p = planes[startPlane];
if ((mask & 1<<startPlane) != 0 && p.x * (p.x < 0 ? minX : maxX) + p.y * (p.y < 0 ? minY : maxY) + p.z * (p.z < 0 ? minZ : maxZ) < -p.w) {
return plane;
}
if ((mask & PLANE_MASK_NX) == 0 || nxX * (nxX < 0 ? minX : maxX) + nxY * (nxY < 0 ? minY : maxY) + nxZ * (nxZ < 0 ? minZ : maxZ) >= -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 <code>a</code> and <code>b</code>,
* is partly or completely within the frustum defined by <code>this</code> frustum culler.
*
* @param a
* the line segment's first end point
* @param b
* the line segment's second end point
* @return <code>true</code> if the given line segment is partly or completely inside the frustum;
* <code>false</code> 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 <code>(aX, aY, aZ)</code> and <code>(bX, bY, bZ)</code>,
* is partly or completely within the frustum defined by <code>this</code> 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 <code>true</code> if the given line segment is partly or completely inside the frustum;
* <code>false</code> 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;
}
public void getCorners(ByteBuffer buffer) {
Vector3f scratch = new Vector3f();
Vector3f result = new Vector3f();
long addr = MemoryUtil.memAddress(buffer);
planeIntersect(planes[0], planes[2], planes[4], result, scratch); result.getToAddress(addr);
planeIntersect(planes[0], planes[2], planes[5], result, scratch); result.getToAddress(addr + 12);
planeIntersect(planes[0], planes[3], planes[4], result, scratch); result.getToAddress(addr + 24);
planeIntersect(planes[0], planes[3], planes[5], result, scratch); result.getToAddress(addr + 36);
planeIntersect(planes[1], planes[2], planes[4], result, scratch); result.getToAddress(addr + 48);
planeIntersect(planes[1], planes[2], planes[5], result, scratch); result.getToAddress(addr + 60);
planeIntersect(planes[1], planes[3], planes[4], result, scratch); result.getToAddress(addr + 72);
planeIntersect(planes[1], planes[3], planes[5], result, scratch); result.getToAddress(addr + 84);
}
private Vector3f planeIntersect(Vector4f a, Vector4f b, Vector4f c, Vector3f result, Vector3f scratch) {
// Formula used
// d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 )
//P = ---------------------------------------------------------------------
// N1 . ( N2 * N3 )
//
// Note: N refers to the normal, d refers to the displacement. '.' means dot product. '*' means cross product
float f = result.set(b.x, b.y, b.z).cross(c.x, c.y, c.z).dot(a.x, a.y, a.z);
result.set(0);
scratch.set(b.x, b.y, b.z).cross(c.x, c.y, c.z).mul(a.z);
result.add(scratch);
scratch.set(c.x, c.y, c.z).cross(a.x, a.y, a.z).mul(b.z);
result.add(scratch);
scratch.set(a.x, a.y, a.z).cross(b.x, b.y, b.z).mul(c.z);
result.add(scratch);
return result.div(f);
}
}

View file

@ -1,154 +0,0 @@
/*
* 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.util.joml;
/**
* Provides methods to compute rays through an arbitrary perspective transformation defined by a {@link Matrix4fc}.
* <p>
* This can be used to compute the eye-rays in simple software-based raycasting/raytracing.
* <p>
* 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.
* <p>
* 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 <code>this</code> {@link FrustumRayBuilder} with the given {@link Matrix4fc matrix}.
* <p>
* Reference: <a href="http://gamedevs.org/uploads/fast-extraction-viewing-frustum-planes-from-world-view-projection-matrix.pdf">
* Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix</a>
* <p>
* Reference: <a href="http://geomalgorithms.com/a05-_intersect-1.html">http://geomalgorithms.com</a>
*
* @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 <code>origin</code>.
*
* @param origin
* will hold the perspective origin
* @return the <code>origin</code> 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.
* <p>
* The parameters <code>x</code> and <code>y</code> 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 <code>[0..1]</code>
* @param y
* the interpolation factor along the bottom-to-top frustum planes, within <code>[0..1]</code>
* @param dir
* will hold the normalized ray direction
* @return the <code>dir</code> 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;
}
}

View file

@ -1,571 +0,0 @@
/*
* 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.util.joml;
/**
* Contains fast approximations of some {@link java.lang.Math} operations.
* <p>
* 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 <code>-Djoml.fastmath</code>.
* <p>
* There are two algorithms for approximating sin/cos:
* <ol>
* <li>arithmetic <a href="http://www.java-gaming.org/topics/joml-1-8-0-release/37491/msg/361815/view.html#msg361815">polynomial approximation</a> contributed by roquendm
* <li>theagentd's <a href="http://www.java-gaming.org/topics/extremely-fast-sine-cosine/36469/msg/346213/view.html#msg346213">linear interpolation</a> variant of Riven's algorithm from
* <a href="http://www.java-gaming.org/topics/extremely-fast-sine-cosine/36469/view.html">http://www.java-gaming.org/</a>
* </ol>
* By default, the first algorithm is being used. In order to use the second one, start the JVM with <code>-Djoml.sinLookup</code>. The lookup table bit length of the second algorithm can also be adjusted
* for improved accuracy via <code>-Djoml.sinLookup.bits=&lt;n&gt;</code>, where &lt;n&gt; 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: <a href="http://www.java-gaming.org/topics/joml-1-8-0-release/37491/msg/361718/view.html#msg361718">http://www.java-gaming.org/</a>
*/
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: <a href="http://www.java-gaming.org/topics/joml-1-8-0-release/37491/msg/361815/view.html#msg361815">http://www.java-gaming.org/</a>
*/
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: <a href="http://www.java-gaming.org/topics/joml-1-8-0-release/37491/msg/361815/view.html#msg361815">http://www.java-gaming.org/</a>
*/
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: <a href="http://www.java-gaming.org/topics/extremely-fast-sine-cosine/36469/msg/349515/view.html#msg349515">http://www.java-gaming.org/</a>
*/
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) {
if (Options.FASTMATH) {
if (Options.SIN_LOOKUP)
return sin_theagentd_lookup(rad);
return (float) sin_roquen_newk(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;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,186 +0,0 @@
/*
* 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.util.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.
* <p>
* 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 <i>current</i> 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.
* <p>
* 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 <code>this</code>
* {@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.
* <p>
* 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.
* <p>
* 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;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,185 +0,0 @@
/*
* 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.util.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.
* <p>
* 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 <i>current</i> 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.
* <p>
* 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 <code>this</code>
* {@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.
* <p>
* 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.
* <p>
* 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;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
/*
* 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.util.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 <i>not</i> to use sun.misc.Unsafe when copying memory with MemUtil.
*/
public static final boolean NO_UNSAFE = hasOption(System.getProperty("joml.nounsafe", "false"));
/**
* Whether to <i>force</i> 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 <code>true</code>, 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 <code>true</code>, 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 <i>not</i> 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 <code>true</code> 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();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,354 +0,0 @@
/*
* 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.util.joml;
/**
* Computes the weighted average of multiple rotations represented as {@link Quaternionf} instances.
* <p>
* Instances of this class are <i>not</i> thread-safe.
*
* @author Kai Burjack
*/
public class QuaternionfInterpolator {
/**
* Performs singular value decomposition on {@link Matrix3f}.
* <p>
* This code was adapted from <a href="http://www.public.iastate.edu/~dicook/JSS/paper/code/svd.c">http://www.public.iastate.edu/</a>.
*
* @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 <code>qs</code> using the specified interpolation factors <code>weights</code>, and store the result in <code>dest</code>.
*
* @param qs
* the quaternions to interpolate over
* @param weights
* the weights of each individual quaternion in <code>qs</code>
* @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();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,399 +0,0 @@
/*
* 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.util.joml;
/**
* This is an implementation of the <a
* href="http://www.cg.cs.tu-bs.de/media/publications/fast-rayaxis-aligned-bounding-box-overlap-tests-using-ray-slopes.pdf">Fast Ray/Axis-Aligned Bounding Box
* Overlap Tests using Ray Slopes</a> paper.
* <p>
* It is an efficient implementation when testing many axis-aligned boxes against the same ray.
* <p>
* 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.
* <p>
* 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 <code>(originX, originY, originZ)</code>
* and direction <code>(dirX, dirY, dirZ)</code>.
* <p>
* 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 <code>(originX, originY, originZ)</code>
* and direction <code>(dirX, dirY, dirZ)</code>.
*
* @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 <code>(minX, minY, minZ)</code> and its maximum corner <code>(maxX, maxY, maxZ)</code>.
* <p>
* This implementation uses a tableswitch to dispatch to the correct intersection method.
* <p>
* 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 <code>true</code> iff the ray intersects the given axis-aligned box; <code>false</code> 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;
}
}

View file

@ -1,60 +0,0 @@
/*
* 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.util.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;
}

View file

@ -1,148 +0,0 @@
/*
* 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.util.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;
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,805 +0,0 @@
/*
* 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.util.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}.
* <p>
* This method will not increment the position of the given FloatBuffer.
* <p>
* 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 <code>x, y, z, w</code> 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.
* <p>
* 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 <code>x, y, z, w</code> 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}.
* <p>
* This method will not increment the position of the given ByteBuffer.
* <p>
* 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 <code>x, y, z, w</code> 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.
* <p>
* 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 <code>x, y, z, w</code> order
* @return the passed in buffer
*/
ByteBuffer get(int index, ByteBuffer buffer);
/**
* Store this vector at the given off-heap memory address.
* <p>
* This method will throw an {@link UnsupportedOperationException} when JOML is used with `-Djoml.nounsafe`.
* <p>
* <em>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.</em>
*
* @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 <code>dest</code>.
*
* @param v
* the vector to subtract from <code>this</code>
* @param dest
* will hold the result
* @return dest
*/
Vector4f sub(Vector4fc v, Vector4f dest);
/**
* Subtract <code>(x, y, z, w)</code> from this and store the result in <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>a * b</code> to this vector
* and store the result in <code>dest</code>.
*
* @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 <code>a * b</code> to this vector
* and store the result in <code>dest</code>.
*
* @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 <code>this * a</code> to <code>b</code>
* and store the result in <code>dest</code>.
*
* @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 <code>this * a</code> to <code>b</code>
* and store the result in <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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
* <code>dest</code>.
*
* @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 <code>mat</code> with this Vector4f and store the result in
* <code>dest</code>.
*
* @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
* <code>dest</code>.
*
* @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 <code>mat</code> with this Vector4f and store the result in
* <code>dest</code>.
*
* @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 <code>mat</code> with this Vector4f, perform perspective division
* and store the result in <code>dest</code>.
*
* @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 <code>mat</code> with this Vector4f, perform perspective division
* and store the <code>(x, y, z)</code> result in <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>quat</code> and store the result in <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>(x, y, z)</code> and store the result in <code>dest</code>.
*
* @param dest
* will hold the result
* @return dest
*/
Vector4f normalize3(Vector4f dest);
/**
* Return the distance between this Vector and <code>v</code>.
*
* @param v
* the other vector
* @return the distance
*/
float distance(Vector4fc v);
/**
* Return the distance between <code>this</code> vector and <code>(x, y, z, w)</code>.
*
* @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 <code>v</code>.
*
* @param v
* the other vector
* @return the squared of the distance
*/
float distanceSquared(Vector4fc v);
/**
* Return the square of the distance between <code>this</code> vector and
* <code>(x, y, z, w)</code>.
*
* @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 <code>v</code>
* .
*
* @param v
* the other vector
* @return the dot product
*/
float dot(Vector4fc v);
/**
* Compute the dot product (inner product) of this vector and <code>(x, y, z, w)</code>.
*
* @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 <code>Math.cos(angle(v))</code>.
*
* @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 <code>dest</code>.
*
* @param dest
* will hold the result
* @return dest
*/
Vector4f negate(Vector4f dest);
/**
* Set the components of <code>dest</code> 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 <code>dest</code> 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 <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code>
* and store the result in <code>dest</code>.
* <p>
* If <code>t</code> is <code>0.0</code> then the result is <code>this</code>. If the interpolation factor is <code>1.0</code>
* then the result is <code>other</code>.
*
* @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 <code>this</code> vector and the given vector <code>v</code> and
* store the result in <code>dest</code>.
*
* @param v
* the other vector
* @param t
* the interpolation factor, within <code>[0..1]</code>
* @param dest
* will hold the result
* @return dest
*/
Vector4f smoothStep(Vector4fc v, float t, Vector4f dest);
/**
* Compute a hermite interpolation between <code>this</code> vector and its
* associated tangent <code>t0</code> and the given vector <code>v</code>
* with its tangent <code>t1</code> and store the result in
* <code>dest</code>.
*
* @param t0
* the tangent of <code>this</code> vector
* @param v1
* the other vector
* @param t1
* the tangent of the other vector
* @param t
* the interpolation factor, within <code>[0..1]</code>
* @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 <code>[0..3]</code>
* @return the value
* @throws IllegalArgumentException if <code>component</code> is not within <code>[0..3]</code>
*/
float get(int component) throws IllegalArgumentException;
/**
* Set the components of the given vector <code>dest</code> to those of <code>this</code> vector.
*
* @param dest
* will hold the result
* @return dest
*/
Vector4f get(Vector4f dest);
/**
* Determine the component with the biggest absolute value.
*
* @return the component index, within <code>[0..3]</code>
*/
int maxComponent();
/**
* Determine the component with the smallest (towards zero) absolute value.
*
* @return the component index, within <code>[0..3]</code>
*/
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
* <code>dest</code>.
*
* @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
* <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @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 <code>dest</code>.
*
* @param dest
* will hold the result
* @return dest
*/
Vector4f absolute(Vector4f dest);
/**
* Compare the vector components of <code>this</code> vector with the given vector using the given <code>delta</code>
* and return whether all of them are equal within a maximum difference of <code>delta</code>.
* <p>
* 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 <code>true</code> whether all of the vector components are equal; <code>false</code> otherwise
*/
boolean equals(Vector4fc v, float delta);
/**
* Compare the vector components of <code>this</code> vector with the given <code>(x, y, z, w)</code>
* 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 <code>true</code> if all the vector components are equal
*/
boolean equals(float x, float y, float z, float w);
}

View file

@ -5,6 +5,9 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.joml.FrustumIntersection;
import org.joml.Vector3f;
import com.jozufozu.flywheel.api.RenderStage;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
@ -19,8 +22,6 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.box.GridAlignedBB;
import com.jozufozu.flywheel.util.box.ImmutableBox;
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
import com.jozufozu.flywheel.util.joml.Vector3f;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;