vector) {
+ this.vector = vector;
+ }
+
+ @Override
+ public float length() {
+ float total = 0;
+ for (float v : vector) {
+ total+=v*v;
+ }
+ return (float) Math.sqrt(total);
+ }
+
+ public int size() {
+ return vector.size();
+ }
+
+ public float get(int row) {
+ return vector.get(row);
+ }
+
+ @Override
+ public ExtensibleVectorNf duplicate() {
+ return new ExtensibleVectorNf(new ArrayList<>(vector));
+ }
+
+ @Override
+ public OperatingVectorNf div(float number) {
+ vector.replaceAll(aFloat -> aFloat/number);
+ return this;
+ }
+
+ @Override
+ public OperatingVectorNf mul(float number) {
+ vector.replaceAll(aFloat -> aFloat*number);
+ return this;
+ }
+
+ @Override
+ public OperatingVectorNf add(OperatingVectorNf other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ for (int i = 0; i < vector.size(); i++) {
+ vector.set(i, vector.get(i)+other.get(i));
+ }
+ return this;
+ }
+
+ @Override
+ public OperatingVectorNf sub(OperatingVectorNf other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ for (int i = 0; i < vector.size(); i++) {
+ vector.set(i, vector.get(i)-other.get(i));
+ }
+ return this;
+ }
+
+ public void set(int row, float v) {
+ if (row >= vector.size())
+ vector.add(row, v);
+ else
+ vector.set(row, v);
+ }
+
+ public void add(float v) {
+ vector.add(v);
+ }
+
+ public void add(int row, float v) {
+ vector.set(row, getOrZero(row) + v);
+ }
+
+ private Float getOrZero(int row) {
+ return row < vector.size() ? get(row) : 0;
+ }
+
+ public void div(int row, float v) {
+ vector.set(row, getOrZero(row) / v);
+ }
+
+ public void clamp(int row, float min, float max) {
+ vector.set(row, Maths.clamp(getOrZero(row), min, max));
+ }
+
+ @Override
+ public String toString() {
+ return "ExtensibleVectorNf{" +
+ "vector=" + vector +
+ '}';
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java
deleted file mode 100644
index 9bd9c27..0000000
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/Matrix.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package fr.radi3nt.maths.components.matrices;
-
-import fr.radi3nt.maths.components.vectors.Vector3f;
-import fr.radi3nt.maths.components.vectors.Vector4f;
-
-import java.nio.FloatBuffer;
-
-public interface Matrix {
-
- Matrix identity();
- Matrix zero();
-
- Matrix translation(Vector3f vector3f);
-
- /**
- * @param value Angle in radians
- */
- Matrix rotation(float value, Vector3f axis);
- /**
- * @param rotation Angles in radians
- */
- Matrix rotation(Vector3f rotation);
- Matrix scaling(Vector3f scale);
-
- Matrix translate(Vector3f vector3f);
- /**
- * @param value Angle in radians
- */
- Matrix rotate(float value, Vector3f axis);
-
- void rotationFromDirection(Vector3f direction, Vector3f up);
-
- Matrix scale(Vector3f scale);
-
- Matrix invert();
- Matrix transpose();
-
- Vector4f transform(Vector4f vector4f);
-
- Matrix multiply(Matrix matrix);
-
- Matrix mul(Matrix matrix);
-
- Matrix set(int x, int y, float value);
-
- float get(int x, int y);
-
- Matrix store(FloatBuffer buffer);
-
- Matrix duplicate();
-
- void copy(Matrix transform);
-}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java
deleted file mode 100644
index 8676010..0000000
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/PerspectiveMatrix.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package fr.radi3nt.maths.components.matrices;
-
-public interface PerspectiveMatrix extends Matrix {
-
- Matrix perspective(float fov, float aspect, float near, float far);
-
-}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java
deleted file mode 100644
index 13ec6cd..0000000
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/ViewMatrix.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package fr.radi3nt.maths.components.matrices;
-
-import fr.radi3nt.maths.components.vectors.Vector3f;
-
-public interface ViewMatrix extends Matrix {
-
- ViewMatrix view(Vector3f position, Vector3f rotation);
-
-}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java
deleted file mode 100644
index b6bfd10..0000000
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/ArrayMatrix.java
+++ /dev/null
@@ -1,463 +0,0 @@
-package fr.radi3nt.maths.components.matrices.implementation;
-
-import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4;
-import fr.radi3nt.maths.components.matrices.Matrix;
-import fr.radi3nt.maths.components.matrices.PerspectiveMatrix;
-import fr.radi3nt.maths.components.matrices.ViewMatrix;
-import fr.radi3nt.maths.components.vectors.Vector3f;
-import fr.radi3nt.maths.components.vectors.Vector4f;
-import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
-import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f;
-
-import java.nio.FloatBuffer;
-import java.util.Arrays;
-
-public class ArrayMatrix implements Matrix, PerspectiveMatrix, ViewMatrix {
-
- private float[][] m;
-
- ArrayMatrix(float[][] m) {
- this.m = m;
- }
-
- ArrayMatrix() {
- this(new float[4][4]);
- identity();
- }
-
- public static Matrix from(ArrayMatrix4x4 arrayMatrix4x4) {
- ArrayMatrix arrayMatrix = new ArrayMatrix();
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- arrayMatrix.set(i, j, arrayMatrix4x4.get(i, j));
- }
- }
- return arrayMatrix;
- }
-
- public static Matrix fromTransposing(ArrayMatrix4x4 arrayMatrix4x4) {
- ArrayMatrix arrayMatrix = new ArrayMatrix();
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- arrayMatrix.set(i, j, arrayMatrix4x4.get(j, i));
- }
- }
- return arrayMatrix;
- }
-
-
- @Override
- public Matrix identity() {
- m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
- m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = 0;
- m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = 0;
- m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
-
- return this;
- }
-
- @Override
- public Matrix zero() {
- m[0][0] = 0; m[0][1] = 0; m[0][2] = 0; m[0][3] = 0;
- m[1][0] = 0; m[1][1] = 0; m[1][2] = 0; m[1][3] = 0;
- m[2][0] = 0; m[2][1] = 0; m[2][2] = 0; m[2][3] = 0;
- m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 0;
-
- return this;
- }
-
- @Override
- public Matrix translation(Vector3f translation) {
- identity();
- m[0][0] = 1; m[0][1] = 0; m[0][2] = 0; m[0][3] = translation.getX();
- m[1][0] = 0; m[1][1] = 1; m[1][2] = 0; m[1][3] = translation.getY();
- m[2][0] = 0; m[2][1] = 0; m[2][2] = 1; m[2][3] = translation.getZ();
- m[3][0] = 0; m[3][1] = 0; m[3][2] = 0; m[3][3] = 1;
-
- return this;
- }
-
- public static Matrix translate(Vector3f vec, Matrix src, Matrix dest) {
- if (dest == null) {
- dest = new ArrayMatrix();
- }
-
- dest.set(3, 0, dest.get(3, 0) + src.get(0, 0) * vec.getX() + src.get(1, 0) * vec.getY() + src.get(2, 0) * vec.getZ());
- dest.set(3, 1, dest.get(3, 1) + src.get(0, 1) * vec.getX() + src.get(1, 1) * vec.getY() + src.get(2, 1) * vec.getZ());
- dest.set(3, 2, dest.get(3, 2) + src.get(0, 2) * vec.getX() + src.get(1, 2) * vec.getY() + src.get(2, 2) * vec.getZ());
- dest.set(3, 3, dest.get(3, 3) + src.get(0, 3) * vec.getX() + src.get(1, 3) * vec.getY() + src.get(2, 3) * vec.getZ());
- return dest;
- }
-
- @Override
- public Matrix rotation(float value, Vector3f axis) {
- identity();
- return rotate(value, axis, this, this);
- }
-
- public static Matrix rotate(float angle, Vector3f axis, Matrix src, Matrix dest) {
- if (dest == null) {
- dest = new ArrayMatrix();
- }
-
- float c = (float) Math.cos(angle);
- float s = (float) Math.sin(angle);
- float oneminusc = 1.0F - c;
- float xy = axis.getX() * axis.getY();
- float yz = axis.getY() * axis.getZ();
- float xz = axis.getX() * axis.getZ();
- float xs = axis.getX() * s;
- float ys = axis.getY() * s;
- float zs = axis.getZ() * s;
- float f00 = axis.getX() * axis.getX() * oneminusc + c;
- float f01 = xy * oneminusc + zs;
- float f02 = xz * oneminusc - ys;
- float f10 = xy * oneminusc - zs;
- float f11 = axis.getY() * axis.getY() * oneminusc + c;
- float f12 = yz * oneminusc + xs;
- float f20 = xz * oneminusc + ys;
- float f21 = yz * oneminusc - xs;
- float f22 = axis.getZ() * axis.getZ() * oneminusc + c;
- float t00 = src.get(0, 0) * f00 + src.get(1, 0) * f01 + src.get(2, 0) * f02;
- float t01 = src.get(0, 1) * f00 + src.get(1, 1) * f01 + src.get(2, 1) * f02;
- float t02 = src.get(0, 2) * f00 + src.get(1, 2) * f01 + src.get(2, 2) * f02;
- float t03 = src.get(0, 3) * f00 + src.get(1, 3) * f01 + src.get(2, 3) * f02;
- float t10 = src.get(0, 0) * f10 + src.get(1, 0) * f11 + src.get(2, 0) * f12;
- float t11 = src.get(0, 1) * f10 + src.get(1, 1) * f11 + src.get(2, 1) * f12;
- float t12 = src.get(0, 2) * f10 + src.get(1, 2) * f11 + src.get(2, 2) * f12;
- float t13 = src.get(0, 3) * f10 + src.get(1, 3) * f11 + src.get(2, 3) * f12;
- dest.set(2, 0, src.get(0, 0) * f20 + src.get(1, 0) * f21 + src.get(2, 0) * f22);
- dest.set(2, 1, src.get(0, 1) * f20 + src.get(1, 1) * f21 + src.get(2, 1) * f22);
- dest.set(2, 2, src.get(0, 2) * f20 + src.get(1, 2) * f21 + src.get(2, 2) * f22);
- dest.set(2, 3, src.get(0, 3) * f20 + src.get(1, 3) * f21 + src.get(2, 3) * f22);
- dest.set(0, 0, t00);
- dest.set(0, 1, t01);
- dest.set(0, 2, t02);
- dest.set(0, 3, t03);
- dest.set(1, 0, t10);
- dest.set(1, 1, t11);
- dest.set(1, 2, t12);
- dest.set(1, 3, t13);
- return dest;
- }
-
- @Override
- public Matrix rotation(Vector3f rotation) {
- float x = rotation.getX();
- float y = rotation.getY();
- float z = rotation.getZ();
-
- float sinX = (float) Math.sin(x);
- float sinY = (float) Math.sin(y);
- float sinZ = (float) Math.sin(z);
-
- float cosX = (float) Math.cos(x);
- float cosY = (float) Math.cos(y);
- float cosZ = (float) Math.cos(z);
-
- final float sinXsinY = sinX * sinY;
- final float cosXsinY = cosX * sinY;
-
- m[0][0] = cosY * cosZ;
- m[0][1] = cosY * sinZ;
- m[0][2] = -sinY;
- m[0][3] = 0f;
-
- m[1][0] = sinXsinY * cosZ - cosX * sinZ;
- m[1][1] = sinXsinY * sinZ + cosX * cosZ;
- m[1][2] = sinX * cosY;
- m[1][3] = 0f;
-
- m[2][0] = cosXsinY * cosZ + sinX * sinZ;
- m[2][1] = cosXsinY * sinZ - sinX * cosZ;
- m[2][2] = cosX * cosY;
- m[2][3] = 0f;
-
- m[3][0] = 0f;
- m[3][1] = 0f;
- m[3][2] = 0f;
- m[3][3] = 1f;
-
- return this;
- }
-
- @Override
- public Matrix scaling(Vector3f scale) {
- identity();
- return scale(scale, this, this);
- }
-
- public static Matrix scale(Vector3f vec, Matrix src, Matrix dest) {
- if (dest == null) {
- dest = new ArrayMatrix();
- }
-
- dest.set(0, 0, src.get(0, 0)*vec.getX());
- dest.set(0, 1, src.get(0, 1)*vec.getX());
- dest.set(0, 2, src.get(0, 2)*vec.getX());
- dest.set(0, 3, src.get(0, 3)*vec.getX());
-
- dest.set(1, 0, src.get(1, 0)*vec.getY());
- dest.set(1, 1, src.get(1, 1)*vec.getY());
- dest.set(1, 2, src.get(1, 2)*vec.getY());
- dest.set(1, 3, src.get(1, 3)*vec.getY());
-
- dest.set(2, 0, src.get(2, 0)*vec.getZ());
- dest.set(2, 1, src.get(2, 1)*vec.getZ());
- dest.set(2, 2, src.get(2, 2)*vec.getZ());
- dest.set(2, 3, src.get(2, 3)*vec.getZ());
-
- return dest;
- }
-
- @Override
- public Matrix translate(Vector3f vector3f) {
- return translate(vector3f, this, this);
- }
-
- @Override
- public Matrix rotate(float value, Vector3f axis) {
- return rotate(value, axis, this, this);
- }
-
- @Override
- public void rotationFromDirection(Vector3f direction, Vector3f up) {
- Vector3f xaxis = up.duplicate().cross(direction);
- xaxis.normalize();
-
- Vector3f yaxis = direction.duplicate().cross(xaxis);
- yaxis.normalize();
-
- m[0][0] = xaxis.getX();
- m[0][1] = yaxis.getX();
- m[0][2] = direction.getX();
-
- m[1][0] = xaxis.getY();
- m[1][1] = yaxis.getY();
- m[1][2] = direction.getY();
-
- m[2][0] = xaxis.getZ();
- m[2][1] = yaxis.getZ();
- m[2][2] = direction.getZ();
- }
-
- @Override
- public Matrix scale(Vector3f scale) {
- return scale(scale, this, this);
- }
-
- @Override
- public Vector4f transform(Vector4f vector4f) {
- float x = this.m[0][0] * vector4f.getX() + this.m[1][0] * vector4f.getY() + this.m[2][0] * vector4f.getZ() + this.m[3][0] * vector4f.getW();
- float y = this.m[0][1] * vector4f.getX() + this.m[1][1] * vector4f.getY() + this.m[2][1] * vector4f.getZ() + this.m[3][1] * vector4f.getW();
- float z = this.m[0][2] * vector4f.getX() + this.m[1][2] * vector4f.getY() + this.m[2][2] * vector4f.getZ() + this.m[3][2] * vector4f.getW();
- float w = this.m[0][3] * vector4f.getX() + this.m[1][3] * vector4f.getY() + this.m[2][3] * vector4f.getZ() + this.m[3][3] * vector4f.getW();
- return new SimpleVector4f(x, y, z, w);
- }
-
- @Override
- public Matrix invert() {
- float s0 = get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1);
- float s1 = get(0, 0) * get(1, 2) - get(1, 0) * get(0, 2);
- float s2 = get(0, 0) * get(1, 3) - get(1, 0) * get(0, 3);
- float s3 = get(0, 1) * get(1, 2) - get(1, 1) * get(0, 2);
- float s4 = get(0, 1) * get(1, 3) - get(1, 1) * get(0, 3);
- float s5 = get(0, 2) * get(1, 3) - get(1, 2) * get(0, 3);
-
- float c5 = get(2, 2) * get(3, 3) - get(3, 2) * get(2, 3);
- float c4 = get(2, 1) * get(3, 3) - get(3, 1) * get(2, 3);
- float c3 = get(2, 1) * get(3, 2) - get(3, 1) * get(2, 2);
- float c2 = get(2, 0) * get(3, 3) - get(3, 0) * get(2, 3);
- float c1 = get(2, 0) * get(3, 2) - get(3, 0) * get(2, 2);
- float c0 = get(2, 0) * get(3, 1) - get(3, 0) * get(2, 1);
-
-
- float div = (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0);
- if (div == 0) System.err.println("not invertible");
-
- float invdet = 1.0f / div;
-
- ArrayMatrix invM = new ArrayMatrix();
-
- invM.set(0, 0, (get(1, 1) * c5 - get(1, 2) * c4 + get(1, 3) * c3) * invdet);
- invM.set(0, 1, (-get(0, 1) * c5 + get(0, 2) * c4 - get(0, 3) * c3) * invdet);
- invM.set(0, 2, (get(3, 1) * s5 - get(3, 2) * s4 + get(3, 3) * s3) * invdet);
- invM.set(0, 3, (-get(2, 1) * s5 + get(2, 2) * s4 - get(2, 3) * s3) * invdet);
-
- invM.set(1, 0, (-get(1, 0) * c5 + get(1, 2) * c2 - get(1, 3) * c1) * invdet);
- invM.set(1, 1, (get(0, 0) * c5 - get(0, 2) * c2 + get(0, 3) * c1) * invdet);
- invM.set(1, 2, (-get(3, 0) * s5 + get(3, 2) * s2 - get(3, 3) * s1) * invdet);
- invM.set(1, 3, (get(2, 0) * s5 - get(2, 2) * s2 + get(2, 3) * s1) * invdet);
-
- invM.set(2, 0, (get(1, 0) * c4 - get(1, 1) * c2 + get(1, 3) * c0) * invdet);
- invM.set(2, 1, (-get(0, 0) * c4 + get(0, 1) * c2 - get(0, 3) * c0) * invdet);
- invM.set(2, 2, (get(3, 0) * s4 - get(3, 1) * s2 + get(3, 3) * s0) * invdet);
- invM.set(2, 3, (-get(2, 0) * s4 + get(2, 1) * s2 - get(2, 3) * s0) * invdet);
-
- invM.set(3, 0, (-get(1, 0) * c3 + get(1, 1) * c1 - get(1, 2) * c0) * invdet);
- invM.set(3, 1, (get(0, 0) * c3 - get(0, 1) * c1 + get(0, 2) * c0) * invdet);
- invM.set(3, 2, (-get(3, 0) * s3 + get(3, 1) * s1 - get(3, 2) * s0) * invdet);
- invM.set(3, 3, (get(2, 0) * s3 - get(2, 1) * s1 + get(2, 2) * s0) * invdet);
-
- this.m = invM.getM();
-
- return this;
- }
-
- @Override
- public Matrix transpose() {
- ArrayMatrix result = new ArrayMatrix();
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- result.set(i, j, get(j, i));
- }
- }
-
- this.m = result.getM();
-
- return result;
- }
-
- @Override
- public Matrix multiply(Matrix matrix) {
- ArrayMatrix res = new ArrayMatrix();
-
- multiply(matrix, res);
-
- m = res.getM();
-
- return this;
- }
-
- @Override
- public Matrix mul(Matrix matrix) {
- Matrix res = new ArrayMatrix();
-
- multiply(matrix, res);
-
- return res;
- }
-
- private void multiply(Matrix matrix, Matrix res) {
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- res.set(i, j, this.get(i, 0) * matrix.get(0, j) +
- this.get(i, 1) * matrix.get(1, j) +
- this.get(i, 2) * matrix.get(2, j) +
- this.get(i, 3) * matrix.get(3, j));
- }
- }
- }
-
- @Override
- public Matrix perspective(float fov, float aspect, float near, float far) {
- identity();
-
- float y_scale = (float) ((1f / Math.tan(Math.toRadians(fov / 2f))));
- float frustum_length = far - near;
-
- set(0, 0, y_scale);
- set(1, 1, y_scale*aspect);
- set(2, 2, -((far + near) / frustum_length));
- set(2, 3, -1);
- set(3, 2, -((2 * near * far) / frustum_length));
- set(3, 3, 0);
-
- return this;
- }
-
- @Override
- public ViewMatrix view(Vector3f position, Vector3f rotation) { //todo rotation no need to negate ?
-
- Matrix rotX = MatrixCreator.createMatrix().rotation(-rotation.getX(), new SimpleVector3f(1, 0, 0));
- Matrix rotY = MatrixCreator.createMatrix().rotation(-rotation.getY(), new SimpleVector3f(0, 1, 0));
- Matrix rotZ = MatrixCreator.createMatrix().rotation(-rotation.getZ(), new SimpleVector3f(0, 0, 1));
-
- Matrix translate = MatrixCreator.createMatrix().translation(new SimpleVector3f(-position.getX(), -position.getY(), -position.getZ()));
-
- identity();
- this.multiply(rotX.mul(rotY).mul(rotZ).mul(translate));
-
- return this;
- }
-
- @Override
- public Matrix store(FloatBuffer buffer) {
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- buffer.put(m[i][j]);
- }
- }
- return this;
- }
-
- @Override
- public Matrix set(int x, int y, float value) {
- m[x][y]=value;
- return this;
- }
-
- @Override
- public float get(int x, int y) {
- return m[x][y];
- }
-
- public float[][] getM() {
- return m;
- }
-
- public void setM(float[][] m) {
- this.m = m;
- }
-
- @Override
- public ViewMatrix duplicate() {
- float[][] m2 = new float[4][4];
-
- for (int x = 0; x < m.length; x++) {
- System.arraycopy(m[x], 0, m2[x], 0, m[x].length);
- }
-
- return new ArrayMatrix(m2);
- }
-
- @Override
- public void copy(Matrix transform) {
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- set(i, j, transform.get(i, j));
- }
- }
- }
-
- @Override
- public String toString() {
- StringBuilder stringBuilder = new StringBuilder("ArrayMatrix{" +
- "\n");
-
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- stringBuilder.append(m[i][j]).append(" ");
- }
- stringBuilder.append("\n");
- }
-
- stringBuilder.append("}");
-
- return stringBuilder.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ArrayMatrix that = (ArrayMatrix) o;
- return Arrays.deepEquals(m, that.m);
- }
-
- @Override
- public int hashCode() {
- return Arrays.deepHashCode(m);
- }
-}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java
deleted file mode 100644
index 20461a2..0000000
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/matrices/implementation/MatrixCreator.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package fr.radi3nt.maths.components.matrices.implementation;
-
-import fr.radi3nt.maths.components.matrices.Matrix;
-import fr.radi3nt.maths.components.matrices.PerspectiveMatrix;
-import fr.radi3nt.maths.components.matrices.ViewMatrix;
-
-public class MatrixCreator {
-
- public static Matrix createMatrix() {
- return new ArrayMatrix();
- }
-
- public static PerspectiveMatrix createProjection() {
- return new ArrayMatrix();
- }
-
- public static ViewMatrix createView() {
- return new ArrayMatrix();
- }
-}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java
index f7e61da..74524aa 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector2f.java
@@ -1,6 +1,8 @@
package fr.radi3nt.maths.components.vectors;
-public interface Vector2f extends Vector {
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
+
+public interface Vector2f extends Vector, OperatingVectorNf {
float getX();
void setX(float x);
@@ -22,8 +24,13 @@ public interface Vector2f extends Vector {
Vector2f div(float mul);
Vector2f clone();
+ Vector2f duplicate();
float dot(Vector2f vector2f);
Vector2f normalize();
+ Vector2f normalizeSafely();
+
+ float lengthSquared();
+ void copy(Vector2f vector2f);
}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java
index cc6e63f..6996dee 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector3f.java
@@ -1,6 +1,8 @@
package fr.radi3nt.maths.components.vectors;
-public interface Vector3f extends Vector {
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
+
+public interface Vector3f extends Vector, OperatingVectorNf {
float getX();
@@ -47,4 +49,14 @@ public interface Vector3f extends Vector {
Vector3f negate();
float lengthSquared();
+
+ void copy(Vector3f vert1);
+
+ void set(Vector3f set);
+
+ void add(int row, float value);
+
+ float get(int row);
+
+ Vector3f normalizeSafely();
}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java
index 319e986..c392041 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/Vector4f.java
@@ -1,6 +1,8 @@
package fr.radi3nt.maths.components.vectors;
-public interface Vector4f extends Vector {
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
+
+public interface Vector4f extends Vector, OperatingVectorNf {
float getX();
void setX(float x);
@@ -11,6 +13,15 @@ public interface Vector4f extends Vector {
float getW();
void setW(float w);
+ Vector4f div(float div);
+ float dot(Vector4f other);
+
void normalize();
-
+
+ void set(Vector3f vector3f, float w);
+ void set(float x, float y, float z, float w);
+ void mul(Vector4f other);
+
+ Vector4f duplicate();
+
}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java
index 21acfe8..dbb6e8a 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector2f.java
@@ -1,5 +1,7 @@
package fr.radi3nt.maths.components.vectors.implementations;
+import fr.radi3nt.maths.components.Vector2D;
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
import fr.radi3nt.maths.components.vectors.Vector2f;
import java.util.Objects;
@@ -17,6 +19,27 @@ public SimpleVector2f(float x, float y) {
public SimpleVector2f() {
}
+ public SimpleVector2f(Vector2D vector) {
+ this.x = (float) vector.getX();
+ this.y = (float) vector.getY();
+ }
+
+ public SimpleVector2f(Vector2f vector) {
+ this.copy(vector);
+ }
+
+ public static float distanceSquared(Vector2f first, Vector2f second) {
+ float x = (first.getX()-second.getX());
+ float y = (first.getY()-second.getY());
+ return x*x + y*y;
+ }
+
+ public static float distance(float x, float y, float xo, float yo) {
+ float xd = x-xo;
+ float yd = y-yo;
+ return (float) Math.sqrt(xd*xd+yd*yd);
+ }
+
@Override
public float getX() {
return x;
@@ -78,6 +101,21 @@ public Vector2f mul(float mul) {
return mul(mul, mul);
}
+ @Override
+ public OperatingVectorNf add(OperatingVectorNf other) {
+ return add(other.get(0), other.get(1));
+ }
+
+ @Override
+ public OperatingVectorNf sub(OperatingVectorNf other) {
+ return sub(other.get(0), other.get(1));
+ }
+
+ @Override
+ public int size() {
+ return 2;
+ }
+
@Override
public Vector2f div(Vector2f vector2f) {
return div(vector2f.getX(), vector2f.getY());
@@ -90,6 +128,18 @@ public Vector2f div(float x, float y) {
return this;
}
+ @Override
+ public float get(int row) {
+ if (row>1 || row<0)
+ throw new UnsupportedOperationException();
+ return row == 0 ? x : y;
+ }
+
+ @Override
+ public Vector2f duplicate() {
+ return clone();
+ }
+
@Override
public Vector2f div(float mul) {
return div(mul, mul);
@@ -110,9 +160,35 @@ public Vector2f normalize() {
return div(length());
}
+ @Override
+ public Vector2f normalizeSafely() {
+ float length = length();
+ if (length==0)
+ mul(0);
+ else
+ div(length);
+ return this;
+ }
+
+ @Override
+ public float lengthSquared() {
+ return x * x + y * y;
+ }
+
+ @Override
+ public void copy(Vector2f vector2f) {
+ this.setX(vector2f.getX());
+ this.setY(vector2f.getY());
+ }
+
@Override
public float length() {
- return (float) Math.sqrt(x * x + y * y);
+ return (float) Math.sqrt(lengthSquared());
+ }
+
+ @Override
+ public void copy(OperatingVectorNf other) {
+ this.copy(new SimpleVector2f(other.get(0), other.get(1)));
}
@Override
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java
index d02e2c6..bc100f4 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3f.java
@@ -1,8 +1,10 @@
package fr.radi3nt.maths.components.vectors.implementations;
import fr.radi3nt.maths.components.Vector3D;
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
import fr.radi3nt.maths.components.vectors.Vector3f;
import fr.radi3nt.maths.components.vectors.Vector3i;
+import fr.radi3nt.maths.components.vectors.Vector4f;
import java.util.Objects;
@@ -33,6 +35,25 @@ public SimpleVector3f(Vector3D multiply) {
this((float) multiply.getX(), (float) multiply.getY(), (float) multiply.getZ());
}
+ public SimpleVector3f(Vector4f vector4f) {
+ this(vector4f.getX(), vector4f.getY(), vector4f.getZ());
+ }
+
+ public SimpleVector3f(double v, double v1, double v2) {
+ this((float) v, (float) v1, (float) v2);
+ }
+
+ public static float distanceSquared(Vector3f first, Vector3f second) {
+ float x = (first.getX()-second.getX());
+ float y = (first.getY()-second.getY());
+ float z = (first.getZ()-second.getZ());
+ return x*x + y*y + z*z;
+ }
+
+ public static float distance(Vector3f first, Vector3f second) {
+ return (float) Math.sqrt(distanceSquared(first, second));
+ }
+
@Override
public float getX() {
return x;
@@ -114,6 +135,31 @@ public Vector3f mul(float mul) {
return mul(mul, mul, mul);
}
+ @Override
+ public OperatingVectorNf add(OperatingVectorNf other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ this.x += other.get(0);
+ this.y += other.get(1);
+ this.z += other.get(2);
+ return this;
+ }
+
+ @Override
+ public OperatingVectorNf sub(OperatingVectorNf other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ this.x -= other.get(0);
+ this.y -= other.get(1);
+ this.z -= other.get(2);
+ return this;
+ }
+
+ @Override
+ public int size() {
+ return 3;
+ }
+
@Override
public Vector3f div(Vector3f vector2f) {
return div(vector2f.getX(), vector2f.getY(), vector2f.getZ());
@@ -173,11 +219,59 @@ public float lengthSquared() {
return x * x + y * y + z * z;
}
+ @Override
+ public void copy(Vector3f vert1) {
+ this.set(vert1.getX(), vert1.getY(), vert1.getZ());
+ }
+
+ @Override
+ public void set(Vector3f set) {
+ this.set(set.getX(), set.getY(), set.getZ());
+ }
+
+ @Override
+ public void add(int row, float value) {
+ if (row == 0)
+ x += value;
+ if (row == 1)
+ y += value;
+ if (row == 2)
+ z += value;
+ }
+
+ @Override
+ public float get(int row) {
+ if (row == 0)
+ return x;
+ if (row == 1)
+ return y;
+ if (row == 2)
+ return z;
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public Vector3f normalizeSafely() {
+ if (this.lengthSquared()!=0)
+ this.normalize();
+ return this;
+ }
+
@Override
public float length() {
return (float) Math.sqrt(x * x + y * y + z * z);
}
+ @Override
+ public void copy(OperatingVectorNf other) {
+ if (other.size()!=this.size()) {
+ throw new IllegalArgumentException("Other vector doesn't have the same size");
+ }
+ x = other.get(0);
+ y = other.get(1);
+ z = other.get(2);
+ }
+
@Override
public String toString() {
return "SimpleVector3f{" +
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java
index f45407a..004b531 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector3i.java
@@ -1,5 +1,6 @@
package fr.radi3nt.maths.components.vectors.implementations;
+import fr.radi3nt.maths.components.vectors.Vector3f;
import fr.radi3nt.maths.components.vectors.Vector3i;
public class SimpleVector3i implements Vector3i {
@@ -21,6 +22,16 @@ public SimpleVector3i(Vector3i vector3f) {
public SimpleVector3i() {
}
+ public SimpleVector3i(Vector3f position) {
+ this.x = (int) Math.floor(position.getX());
+ this.y = (int) Math.floor(position.getY());
+ this.z = (int) Math.floor(position.getZ());
+ }
+
+ public static Vector3i fromRound(Vector3f start) {
+ return new SimpleVector3i(Math.round(start.getX()), Math.round(start.getY()), Math.round(start.getZ()));
+ }
+
@Override
public int getX() {
return x;
@@ -194,11 +205,20 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + x;
- result = prime * result + y;
- result = prime * result + z;
- return result;
+ int seed = 3;
+ {
+ seed = getSeed(this.x, seed);
+ seed = getSeed(this.y, seed);
+ seed = getSeed(this.z, seed);
+ }
+ return seed;
+ }
+
+ private static int getSeed(int number, int seed) {
+ int x = ((number >> 16) ^ number) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+ seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
}
}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java
index 2f45f54..48ef9fe 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/components/vectors/implementations/SimpleVector4f.java
@@ -1,5 +1,8 @@
package fr.radi3nt.maths.components.vectors.implementations;
+import fr.radi3nt.maths.components.advanced.quaternions.Quaternion;
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
+import fr.radi3nt.maths.components.vectors.Vector3f;
import fr.radi3nt.maths.components.vectors.Vector4f;
public class SimpleVector4f implements Vector4f {
@@ -16,9 +19,34 @@ public SimpleVector4f(float x, float y, float z, float w) {
this.w = w;
}
+ public SimpleVector4f(Vector3f vec, float w) {
+ this.x = vec.getX();
+ this.y = vec.getY();
+ this.z = vec.getZ();
+ this.w = w;
+ }
+
+ public SimpleVector4f(float vec, float w) {
+ this.x = vec;
+ this.y = vec;
+ this.z = vec;
+ this.w = w;
+ }
+
public SimpleVector4f() {
}
+ public SimpleVector4f(Quaternion quaternion) {
+ this(quaternion.getX(), quaternion.getY(), quaternion.getZ(), quaternion.getW());
+ }
+
+ public static Vector4f fromAbs(Quaternion quaternion) {
+ Vector4f vector = new SimpleVector4f(quaternion);
+ if (quaternion.getW()<0)
+ vector.mul(-1);
+ return vector;
+ }
+
@Override
public float getX() {
return x;
@@ -64,11 +92,105 @@ public void normalize() {
div(length());
}
- private void div(float length) {
+ @Override
+ public void set(Vector3f vector3f, float w) {
+ setX(vector3f.getX());
+ setY(vector3f.getY());
+ setZ(vector3f.getZ());
+ setW(w);
+ }
+
+ @Override
+ public void set(float x, float y, float z, float w) {
+ setX(x);
+ setY(y);
+ setZ(z);
+ setW(w);
+ }
+
+ @Override
+ public void mul(Vector4f other) {
+ this.x *= other.getX();
+ this.y *= other.getY();
+ this.z *= other.getZ();
+ this.w *= other.getW();
+ }
+
+ @Override
+ public float get(int row) {
+ if (row==0)
+ return x;
+ if (row==1)
+ return y;
+ if (row==2)
+ return z;
+ if (row==3)
+ return w;
+ throw new IllegalArgumentException();
+ }
+
+ @Override
+ public Vector4f duplicate() {
+ return new SimpleVector4f(x, y, z, w);
+ }
+
+ public Vector4f div(float length) {
this.setX(getX()/length);
this.setY(getY()/length);
this.setZ(getZ()/length);
this.setW(getW()/length);
+ return this;
+ }
+
+ @Override
+ public float dot(Vector4f other) {
+ return x * other.getX() + y * other.getY() + z * other.getZ() + w * other.getW();
+ }
+
+ @Override
+ public OperatingVectorNf mul(float number) {
+ this.setX(getX()*number);
+ this.setY(getY()*number);
+ this.setZ(getZ()*number);
+ this.setW(getW()*number);
+ return this;
+ }
+
+ @Override
+ public OperatingVectorNf add(OperatingVectorNf other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ this.x += other.get(0);
+ this.y += other.get(1);
+ this.z += other.get(2);
+ this.w += other.get(3);
+ return this;
+ }
+
+ @Override
+ public OperatingVectorNf sub(OperatingVectorNf other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ this.x -= other.get(0);
+ this.y -= other.get(1);
+ this.z -= other.get(2);
+ this.w -= other.get(3);
+ return this;
+ }
+
+ public Vector4f sub(Vector4f other) {
+ if (other.size()!=this.size())
+ throw new IllegalArgumentException();
+ this.x -= other.getX();
+ this.y -= other.getY();
+ this.z -= other.getZ();
+ this.w -= other.getW();
+ return this;
+ }
+
+ @Override
+ public int size() {
+ return 4;
}
@Override
@@ -76,6 +198,17 @@ public float length() {
return (float) Math.sqrt(x * x + y * y + z * z + w * w);
}
+ @Override
+ public void copy(OperatingVectorNf other) {
+ if (other.size()!=this.size()) {
+ throw new IllegalArgumentException("Other vector doesn't have the same size");
+ }
+ x = other.get(0);
+ y = other.get(1);
+ z = other.get(2);
+ w = other.get(3);
+ }
+
@Override
public String toString() {
return "SimpleVector4f{" +
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java
new file mode 100644
index 0000000..0c8fd1b
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/SmoothTransform.java
@@ -0,0 +1,28 @@
+package fr.radi3nt.maths.dynamics;
+
+import fr.radi3nt.maths.components.advanced.quaternions.Quaternion;
+import fr.radi3nt.maths.components.vectors.Vector3f;
+
+public interface SmoothTransform {
+
+ Vector3f getTargetPosition();
+ Quaternion getTargetOrientation();
+
+ Vector3f getCurrentPosition();
+ Quaternion getCurrentOrientation();
+
+ void setCurrentPosition(Vector3f position);
+ void setCurrentOrientation(Quaternion orientation);
+
+ void setTargetPosition(Vector3f position);
+ void setTargetOrientation(Quaternion orientation);
+
+ void setLinearProperties(P linear);
+ void setAngularProperties(P angular);
+ default void setAllProperties(P properties) {
+ setLinearProperties(properties);
+ setAngularProperties(properties);
+ }
+
+ void update(float delta);
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java
new file mode 100644
index 0000000..70a65db
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/AdvancedSmoothTransform.java
@@ -0,0 +1,141 @@
+package fr.radi3nt.maths.dynamics.advanced;
+
+import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion;
+import fr.radi3nt.maths.components.advanced.quaternions.Quaternion;
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.Vector4f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f;
+import fr.radi3nt.maths.dynamics.SmoothTransform;
+
+public class AdvancedSmoothTransform implements SmoothTransform {
+
+ protected final VectorSmoothDynamics positionDynamics;
+ protected final VectorRotationSmoothDynamics rotationDynamics;
+
+ public final Vector3f targetPosition = new SimpleVector3f();
+ public final Quaternion targetRotation = ComponentsQuaternion.zero();
+
+ private final Vector3f position = new SimpleVector3f();
+ private final Quaternion rotation = ComponentsQuaternion.zero();
+
+ public AdvancedSmoothTransform(DynamicsConstants constants) {
+ this.positionDynamics = new VectorSmoothDynamics<>(constants, new SimpleVector3f());
+ this.rotationDynamics = new VectorRotationSmoothDynamics(constants, new SimpleVector4f(0, 0, 0, 1), true);
+ }
+
+ public AdvancedSmoothTransform(DynamicsConstants position, DynamicsConstants rotation) {
+ this.positionDynamics = new VectorSmoothDynamics<>(position, new SimpleVector3f());
+ this.rotationDynamics = new VectorRotationSmoothDynamics(rotation, new SimpleVector4f(0, 0, 0, 1), true);
+ }
+
+ public AdvancedSmoothTransform(Vector3f position, Quaternion rotation, DynamicsConstants positionConstants, DynamicsConstants rotationConstants) {
+ targetPosition.copy(position);
+ targetRotation.copy(rotation);
+
+ this.position.copy(position);
+ this.rotation.copy(rotation);
+
+ this.positionDynamics = new VectorSmoothDynamics<>(positionConstants, targetPosition);
+ this.rotationDynamics = new VectorRotationSmoothDynamics(rotationConstants, new SimpleVector4f(targetRotation), true);
+ }
+
+ public void reset(Vector3f pos, Quaternion rotation) {
+ this.targetPosition.copy(pos);
+ this.position.copy(pos);
+
+ this.rotation.copy(rotation);
+ this.targetRotation.copy(rotation);
+
+ this.positionDynamics.reset(targetPosition);
+ Vector4f currentRot = new SimpleVector4f(rotation);
+ this.rotationDynamics.reset(currentRot);
+ }
+
+ @Override
+ public Vector3f getTargetPosition() {
+ return targetPosition;
+ }
+
+ @Override
+ public Quaternion getTargetOrientation() {
+ return targetRotation;
+ }
+
+ @Override
+ public Vector3f getCurrentPosition() {
+ return position;
+ }
+
+ @Override
+ public Quaternion getCurrentOrientation() {
+ return rotation;
+ }
+
+ @Override
+ public void setCurrentPosition(Vector3f position) {
+ this.positionDynamics.setCurrent(position);
+ }
+
+ @Override
+ public void setCurrentOrientation(Quaternion orientation) {
+ this.rotationDynamics.setCurrent(new SimpleVector4f(orientation));
+ }
+
+ @Override
+ public void setTargetPosition(Vector3f position) {
+ this.targetPosition.copy(position);
+ }
+
+ @Override
+ public void setTargetOrientation(Quaternion orientation) {
+ this.targetRotation.copy(orientation);
+ }
+
+ @Override
+ public void setLinearProperties(DynamicsConstants linear) {
+ positionDynamics.setConstants(linear);
+ }
+
+ @Override
+ public void setAngularProperties(DynamicsConstants angular) {
+ rotationDynamics.setConstants(angular);
+ }
+
+ public void update(float delta) {
+ positionDynamics.setInputCurrent(targetPosition);
+ rotationDynamics.setInputCurrent(new SimpleVector4f(targetRotation));
+
+ positionDynamics.update(delta);
+ rotationDynamics.update(delta);
+
+ this.position.copy(positionDynamics.getResponse());
+ this.rotation.copy(rotationDynamics.getResponse());
+ }
+
+ public Vector3f getLinearVelocity() {
+ return positionDynamics.getResponseDerivative();
+ }
+
+ public Vector3f getPosition() {
+ return position;
+ }
+
+ public Quaternion getRotation() {
+ return rotation;
+ }
+
+ public void setConstants(DynamicsConstants constants) {
+ positionDynamics.setConstants(constants);
+ rotationDynamics.setConstants(constants);
+ }
+
+ public void setPositionConstants(DynamicsConstants constants) {
+ positionDynamics.setConstants(constants);
+ }
+
+ public void setRotationConstants(DynamicsConstants constants) {
+ rotationDynamics.setConstants(constants);
+ }
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DirectionRotationSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DirectionRotationSmoothDynamics.java
new file mode 100644
index 0000000..9cae97e
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DirectionRotationSmoothDynamics.java
@@ -0,0 +1,16 @@
+package fr.radi3nt.maths.dynamics.advanced;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+
+public class DirectionRotationSmoothDynamics extends VectorSmoothDynamics {
+
+ public DirectionRotationSmoothDynamics(DynamicsConstants constants, Vector3f start) {
+ super(constants, start);
+ }
+
+ @Override
+ public void update(float step) {
+ super.update(step);
+ response.normalizeSafely();
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DynamicsConstants.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DynamicsConstants.java
new file mode 100644
index 0000000..9424452
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/DynamicsConstants.java
@@ -0,0 +1,70 @@
+package fr.radi3nt.maths.dynamics.advanced;
+
+import static java.lang.Math.PI;
+import static java.lang.Math.abs;
+
+public class DynamicsConstants {
+
+ private final float k1;
+ private final float k2;
+ private final float k3;
+
+ private final float w;
+ private final float z;
+ private final float d;
+
+ public DynamicsConstants(float k1, float k2, float k3, float w, float z, float d) {
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.w = w;
+ this.z = z;
+ this.d = d;
+ }
+
+ /**
+ * @param f frequency, speed at which the system responds to inputs
+ * @param z damping coefficient, it controls the vibration
+ * @param r initial response,
+ *
+ * - r>0 imply that the system reacts instantly
+ * - r>1 overshoots the input
+ * - r<0 anticipate the motion
+ *
+ */
+ public static DynamicsConstants from(float f, float z, float r) {
+ float w = (float) (2f*PI*f);
+
+ float k1 = (float) (z/(PI * f));
+ float k2 = 1f/ (w*w);
+ float k3 = r * z / w;
+
+ float d = (float) (w * Math.sqrt(abs(z*z-1)));
+
+ return new DynamicsConstants(k1, k2, k3, w, z, d);
+ }
+
+ public float getW() {
+ return w;
+ }
+
+ public float getZ() {
+ return z;
+ }
+
+ public float getD() {
+ return d;
+ }
+
+ public float getK1() {
+ return k1;
+ }
+
+ public float getK2() {
+ return k2;
+ }
+
+ public float getK3() {
+ return k3;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/FloatSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/FloatSmoothDynamics.java
new file mode 100644
index 0000000..7b31f06
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/FloatSmoothDynamics.java
@@ -0,0 +1,79 @@
+package fr.radi3nt.maths.dynamics.advanced;
+
+public class FloatSmoothDynamics {
+
+ private DynamicsConstants constants;
+ protected float inputPrevious, inputCurrent;
+ protected float response, responseDerivative;
+
+ public FloatSmoothDynamics(DynamicsConstants constants, float start) {
+ this.constants = constants;
+ this.response = start;
+ this.inputCurrent = start;
+ this.inputPrevious = start;
+ responseDerivative = 0;
+ }
+
+ public void update(float step) {
+ if (step==0)
+ return;
+ float inputDerivative = (inputCurrent - inputPrevious)/step;
+ inputPrevious = inputCurrent;
+ float k1Stable, k2Stable;
+ if (systemIsAtHighSpeed(constants, step)) {
+ k1Stable = constants.getK1();
+ k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable));
+ } else {
+ k1Stable = constants.getK1();
+ k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable));
+ }
+
+ response+=responseDerivative*step;
+ float multipliedByTTerm = (inputDerivative*constants.getK3()+inputCurrent-response)*step;
+ responseDerivative = (multipliedByTTerm+responseDerivative*k2Stable)/(k2Stable+step*k1Stable);
+ }
+
+ public float getResponseDerivative() {
+ return responseDerivative;
+ }
+
+ public void setInputCurrent(float inputCurrent) {
+ this.inputCurrent = inputCurrent;
+ }
+
+ public float getResponse() {
+ return response;
+ }
+
+ public float getInputCurrent() {
+ return inputCurrent;
+ }
+
+ private boolean systemIsAtHighSpeed(DynamicsConstants constants, float step) {
+ return constants.getW()*step >= constants.getZ();
+ }
+
+ public void setConstants(DynamicsConstants constants) {
+ this.constants = constants;
+ }
+
+ public void setCurrent(float currentLocalPos) {
+ response = currentLocalPos;
+ responseDerivative = 0;
+ }
+
+ public void setCurrentBypass(float currentLocalPos) {
+ response = currentLocalPos;
+ }
+
+ public void setCurrentAll(float currentLocalPos, float responseDerivative) {
+ response = currentLocalPos;
+ inputCurrent = currentLocalPos;
+ inputPrevious = currentLocalPos;
+ this.responseDerivative = responseDerivative;
+ }
+
+ public void setResponseDerivative(float derivative) {
+ this.responseDerivative = derivative;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorRotationSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorRotationSmoothDynamics.java
new file mode 100644
index 0000000..6423d16
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorRotationSmoothDynamics.java
@@ -0,0 +1,32 @@
+package fr.radi3nt.maths.dynamics.advanced;
+
+import fr.radi3nt.maths.components.vectors.Vector4f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector4f;
+
+public class VectorRotationSmoothDynamics extends VectorSmoothDynamics {
+
+ private final boolean loop;
+
+ public VectorRotationSmoothDynamics(DynamicsConstants constants, Vector4f start) {
+ this(constants, start, true);
+ }
+
+ public VectorRotationSmoothDynamics(DynamicsConstants constants, Vector4f start, boolean loop) {
+ super(constants, start);
+ this.loop = loop;
+ }
+
+ @Override
+ public void update(float step) {
+ if (loop && inputPrevious.dot(inputCurrent)<0) {
+ inputCurrent.mul(-1);
+ }
+
+ super.update(step);
+ response.normalize();
+ }
+
+ public void setCurrentBypass(SimpleVector4f current) {
+ this.response = current;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorSmoothDynamics.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorSmoothDynamics.java
new file mode 100644
index 0000000..bc83338
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/advanced/VectorSmoothDynamics.java
@@ -0,0 +1,109 @@
+package fr.radi3nt.maths.dynamics.advanced;
+
+import fr.radi3nt.maths.components.arbitrary.OperatingVectorNf;
+
+public class VectorSmoothDynamics {
+
+ private DynamicsConstants constants;
+ protected T inputPrevious, inputCurrent;
+ protected T response, responseDerivative;
+
+ private final T inputVelocity;
+ private final T inputDerivativeCache;
+ private final T responseDerivativeCache;
+
+ private float speed = 0;
+
+ public VectorSmoothDynamics(DynamicsConstants constants, T start) {
+ this.constants = constants;
+ this.response = (T) start.duplicate();
+ this.inputCurrent = (T) start.duplicate();
+ this.inputPrevious = (T) start.duplicate();
+ responseDerivative = (T) start.duplicate().mul(0);
+ inputDerivativeCache = (T) start.duplicate().mul(0);
+ inputVelocity = (T) start.duplicate().mul(0);
+ responseDerivativeCache = (T) start.duplicate().mul(0);
+ }
+
+ public void update(float step) {
+ if (step==0)
+ return;
+ inputDerivativeCache.copy(inputCurrent);
+ inputDerivativeCache.sub(inputPrevious).div(step);
+ inputDerivativeCache.add(inputVelocity);
+ inputVelocity.mul(0);
+
+ inputPrevious.copy(inputCurrent);
+ float k1Stable, k2Stable;
+ if (systemIsAtHighSpeed(constants, step)) {
+ k1Stable = constants.getK1();
+ k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable)); //todo use pole matching
+ } else {
+ k1Stable = constants.getK1();
+ k2Stable = Math.max(constants.getK2(), Math.max(step*step/2 + step*k1Stable/2, step*k1Stable));
+ }
+
+ responseDerivativeCache.copy(responseDerivative);
+ response.add(responseDerivativeCache.mul(step));
+ responseDerivativeCache.copy(responseDerivative);
+
+ OperatingVectorNf multipliedByTTerm = inputDerivativeCache.mul(constants.getK3()).add(inputCurrent).sub(response).mul(step);
+ responseDerivative.copy(multipliedByTTerm.add(responseDerivativeCache.mul(k2Stable)).div(k2Stable+step*k1Stable));
+ speed = responseDerivative.length();
+ }
+
+ public T getResponseDerivative() {
+ return responseDerivative;
+ }
+
+ public float getSpeed() {
+ return speed;
+ }
+
+ public void setInputCurrent(T inputCurrent) {
+ this.inputCurrent = inputCurrent;
+ }
+
+ public T getInputCurrent() {
+ return inputCurrent;
+ }
+
+ public T getResponse() {
+ return response;
+ }
+
+ private boolean systemIsAtHighSpeed(DynamicsConstants constants, float step) {
+ return constants.getW()*step >= constants.getZ();
+ }
+
+ public void setConstants(DynamicsConstants constants) {
+ this.constants = constants;
+ }
+
+ public void setCurrent(T currentLocalPos) {
+ response = currentLocalPos;
+ responseDerivative = (T) currentLocalPos.duplicate().mul(0);
+ speed = 0;
+ }
+
+ public void reset(T currentLocalPos) {
+ response.copy(currentLocalPos);
+ inputCurrent.copy(currentLocalPos);
+ inputPrevious.copy(currentLocalPos);
+
+ responseDerivative = (T) currentLocalPos.duplicate().mul(0);
+ speed = 0;
+ }
+
+ public T getInputPrevious() {
+ return inputPrevious;
+ }
+
+ public T getInputVelocity() {
+ return inputVelocity;
+ }
+
+ public void setInputPrevious(T inputPrevious) {
+ this.inputPrevious = inputPrevious;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java
new file mode 100644
index 0000000..69c8362
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/DynamicValueFactory.java
@@ -0,0 +1,8 @@
+package fr.radi3nt.maths.dynamics.values;
+
+public interface DynamicValueFactory> {
+
+ T createDynamicValue(P param);
+ ValueDynamicArray
createDynamicValue(P param, int amount);
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java
new file mode 100644
index 0000000..29f9d94
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/TargetValueDynamic.java
@@ -0,0 +1,33 @@
+package fr.radi3nt.maths.dynamics.values;
+
+public abstract class TargetValueDynamic
implements ValueDynamic
{
+
+ protected P properties;
+
+ protected float targetValue;
+ protected float currentValue;
+
+ public TargetValueDynamic(P properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void setTargetValue(float value) {
+ this.targetValue = value;
+ }
+
+ @Override
+ public void setCurrentValue(float value) {
+ this.currentValue = value;
+ }
+
+ @Override
+ public float getCurrentValue() {
+ return currentValue;
+ }
+
+ @Override
+ public void setProperties(P properties) {
+ this.properties = properties;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java
new file mode 100644
index 0000000..e4834a9
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamic.java
@@ -0,0 +1,13 @@
+package fr.radi3nt.maths.dynamics.values;
+
+public interface ValueDynamic
{
+
+ void setTargetValue(float value);
+ void setCurrentValue(float value);
+
+ float getCurrentValue();
+ void update(float delta);
+
+ void setProperties(P properties);
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java
new file mode 100644
index 0000000..71c53a1
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicArray.java
@@ -0,0 +1,26 @@
+package fr.radi3nt.maths.dynamics.values;
+
+public class ValueDynamicArray
> {
+
+ private final T[] values;
+
+ public ValueDynamicArray(T[] values) {
+ this.values = values;
+ }
+
+ public void setProperties(P properties) {
+ for (T value : values) {
+ value.setProperties(properties);
+ }
+ }
+
+ public void update(float delta) {
+ for (T value : values) {
+ value.update(delta);
+ }
+ }
+
+ public T get(int index) {
+ return values[index];
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java
new file mode 100644
index 0000000..679dfa0
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothDirection.java
@@ -0,0 +1,56 @@
+package fr.radi3nt.maths.dynamics.values;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+
+public class ValueDynamicSmoothDirection
> {
+
+ private final Vector3f targetDirection = new SimpleVector3f();
+
+ private final Vector3f direction = new SimpleVector3f();
+
+ private final ValueDynamicArray
positionDynamic;
+
+ public ValueDynamicSmoothDirection(DynamicValueFactory
factory, P linear) {
+ this.positionDynamic = factory.createDynamicValue(linear, 3);
+ }
+
+ public Vector3f getTargetDirection() {
+ return targetDirection;
+ }
+
+ public Vector3f getCurrentDirection() {
+ return direction;
+ }
+
+ public void setCurrentDirection(Vector3f direction) {
+ this.direction.set(direction);
+ this.positionDynamic.get(0).setCurrentValue(direction.getX());
+ this.positionDynamic.get(1).setCurrentValue(direction.getY());
+ this.positionDynamic.get(2).setCurrentValue(direction.getZ());
+ }
+
+ public void setTargetDirection(Vector3f direction) {
+ targetDirection.copy(direction);
+ this.positionDynamic.get(0).setTargetValue(targetDirection.getX());
+ this.positionDynamic.get(1).setTargetValue(targetDirection.getY());
+ this.positionDynamic.get(2).setTargetValue(targetDirection.getZ());
+ }
+
+ public void setLinearProperties(P linear) {
+ this.positionDynamic.setProperties(linear);
+ }
+
+
+ public void update(float delta) {
+ positionDynamic.update(delta);
+
+ this.direction.set(positionDynamic.get(0).getCurrentValue(),
+ positionDynamic.get(1).getCurrentValue(),
+ positionDynamic.get(2).getCurrentValue());
+ this.direction.normalizeSafely();
+ this.positionDynamic.get(0).setCurrentValue(direction.getX());
+ this.positionDynamic.get(1).setCurrentValue(direction.getY());
+ this.positionDynamic.get(2).setCurrentValue(direction.getZ());
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java
new file mode 100644
index 0000000..24fb4da
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothPosition.java
@@ -0,0 +1,55 @@
+package fr.radi3nt.maths.dynamics.values;
+
+import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion;
+import fr.radi3nt.maths.components.advanced.quaternions.Quaternion;
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+import fr.radi3nt.maths.dynamics.SmoothTransform;
+
+public class ValueDynamicSmoothPosition
> {
+
+ private final Vector3f targetPosition = new SimpleVector3f();
+
+ private final Vector3f position = new SimpleVector3f();
+
+ private final ValueDynamicArray
positionDynamic;
+
+ public ValueDynamicSmoothPosition(DynamicValueFactory
factory, P linear) {
+ this.positionDynamic = factory.createDynamicValue(linear, 3);
+ }
+
+ public Vector3f getTargetPosition() {
+ return targetPosition;
+ }
+
+ public Vector3f getCurrentPosition() {
+ return position;
+ }
+
+ public void setCurrentPosition(Vector3f position) {
+ this.position.set(position);
+ this.positionDynamic.get(0).setCurrentValue(position.getX());
+ this.positionDynamic.get(1).setCurrentValue(position.getY());
+ this.positionDynamic.get(2).setCurrentValue(position.getZ());
+ }
+
+ public void setTargetPosition(Vector3f position) {
+ targetPosition.copy(position);
+ this.positionDynamic.get(0).setTargetValue(targetPosition.getX());
+ this.positionDynamic.get(1).setTargetValue(targetPosition.getY());
+ this.positionDynamic.get(2).setTargetValue(targetPosition.getZ());
+ }
+
+ public void setLinearProperties(P linear) {
+ this.positionDynamic.setProperties(linear);
+ }
+
+
+ public void update(float delta) {
+ positionDynamic.update(delta);
+
+ this.position.set(positionDynamic.get(0).getCurrentValue(),
+ positionDynamic.get(1).getCurrentValue(),
+ positionDynamic.get(2).getCurrentValue());
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java
new file mode 100644
index 0000000..783bf6b
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/ValueDynamicSmoothTransform.java
@@ -0,0 +1,112 @@
+package fr.radi3nt.maths.dynamics.values;
+
+import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion;
+import fr.radi3nt.maths.components.advanced.quaternions.Quaternion;
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+import fr.radi3nt.maths.dynamics.SmoothTransform;
+
+public class ValueDynamicSmoothTransform
> implements SmoothTransform
{
+
+ private final Vector3f targetPosition = new SimpleVector3f();
+ private final Quaternion targetOrientation = ComponentsQuaternion.zero();
+
+ private final Vector3f position = new SimpleVector3f();
+ private final Quaternion orientation = ComponentsQuaternion.zero();
+
+ private final ValueDynamicArray
positionDynamic;
+ private final ValueDynamicArray
rotationDynamic;
+
+ public ValueDynamicSmoothTransform(DynamicValueFactory
factory, P linear, P angular) {
+ this.positionDynamic = factory.createDynamicValue(linear, 3);
+ this.rotationDynamic = factory.createDynamicValue(angular, 4);
+ }
+
+ @Override
+ public Vector3f getTargetPosition() {
+ return targetPosition;
+ }
+
+ @Override
+ public Quaternion getTargetOrientation() {
+ return targetOrientation;
+ }
+
+ @Override
+ public Vector3f getCurrentPosition() {
+ return position;
+ }
+
+ @Override
+ public Quaternion getCurrentOrientation() {
+ return orientation;
+ }
+
+ @Override
+ public void setCurrentPosition(Vector3f position) {
+ this.position.set(position);
+ this.positionDynamic.get(0).setCurrentValue(position.getX());
+ this.positionDynamic.get(1).setCurrentValue(position.getY());
+ this.positionDynamic.get(2).setCurrentValue(position.getZ());
+ }
+
+ @Override
+ public void setCurrentOrientation(Quaternion orientation) {
+ this.orientation.copy(orientation);
+ }
+
+ @Override
+ public void setTargetPosition(Vector3f position) {
+ targetPosition.copy(position);
+ this.positionDynamic.get(0).setTargetValue(targetPosition.getX());
+ this.positionDynamic.get(1).setTargetValue(targetPosition.getY());
+ this.positionDynamic.get(2).setTargetValue(targetPosition.getZ());
+ }
+
+ @Override
+ public void setTargetOrientation(Quaternion orientation) {
+ targetOrientation.copy(orientation);
+ }
+
+ @Override
+ public void setLinearProperties(P linear) {
+ this.positionDynamic.setProperties(linear);
+ }
+
+ @Override
+ public void setAngularProperties(P angular) {
+ this.rotationDynamic.setProperties(angular);
+ }
+
+ @Override
+ public void update(float delta) {
+ Quaternion currentTarget = targetOrientation.duplicate();
+
+ if (orientation.dot(currentTarget) <= 0) {
+ orientation.multiply(-1f);
+ }
+ this.rotationDynamic.get(0).setCurrentValue(orientation.getX());
+ this.rotationDynamic.get(1).setCurrentValue(orientation.getY());
+ this.rotationDynamic.get(2).setCurrentValue(orientation.getZ());
+ this.rotationDynamic.get(3).setCurrentValue(orientation.getW());
+
+ this.rotationDynamic.get(0).setTargetValue(currentTarget.getX());
+ this.rotationDynamic.get(1).setTargetValue(currentTarget.getY());
+ this.rotationDynamic.get(2).setTargetValue(currentTarget.getZ());
+ this.rotationDynamic.get(3).setTargetValue(currentTarget.getW());
+
+ positionDynamic.update(delta);
+ rotationDynamic.update(delta);
+
+ this.position.set(positionDynamic.get(0).getCurrentValue(),
+ positionDynamic.get(1).getCurrentValue(),
+ positionDynamic.get(2).getCurrentValue());
+
+ this.orientation.set(
+ rotationDynamic.get(0).getCurrentValue(),
+ rotationDynamic.get(1).getCurrentValue(),
+ rotationDynamic.get(2).getCurrentValue(),
+ rotationDynamic.get(3).getCurrentValue());
+ this.orientation.normaliseSafely();
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java
new file mode 100644
index 0000000..3d6cf64
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicProperties.java
@@ -0,0 +1,14 @@
+package fr.radi3nt.maths.dynamics.values.automatic;
+
+public class AutomaticDynamicProperties {
+
+ private final float agility;
+
+ public AutomaticDynamicProperties(float agility) {
+ this.agility = agility;
+ }
+
+ public float getAgility() {
+ return agility;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java
new file mode 100644
index 0000000..2b452be
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticDynamicValueFactory.java
@@ -0,0 +1,33 @@
+package fr.radi3nt.maths.dynamics.values.automatic;
+
+import fr.radi3nt.maths.dynamics.values.DynamicValueFactory;
+import fr.radi3nt.maths.dynamics.values.ValueDynamicArray;
+
+public class AutomaticDynamicValueFactory implements DynamicValueFactory {
+
+ public static final DynamicValueFactory DEFAULT = new AutomaticDynamicValueFactory();
+
+ private final float defaultValue;
+
+ public AutomaticDynamicValueFactory(float defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public AutomaticDynamicValueFactory() {
+ this(0);
+ }
+
+ @Override
+ public AutomaticValueDynamic createDynamicValue(AutomaticDynamicProperties param) {
+ return new AutomaticValueDynamic(param, defaultValue);
+ }
+
+ @Override
+ public ValueDynamicArray createDynamicValue(AutomaticDynamicProperties param, int amount) {
+ AutomaticValueDynamic[] values = new AutomaticValueDynamic[amount];
+ for (int i = 0; i < amount; i++) {
+ values[i] = new AutomaticValueDynamic(param, defaultValue);
+ }
+ return new ValueDynamicArray<>(values);
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java
new file mode 100644
index 0000000..90db8c0
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/dynamics/values/automatic/AutomaticValueDynamic.java
@@ -0,0 +1,18 @@
+package fr.radi3nt.maths.dynamics.values.automatic;
+
+import fr.radi3nt.maths.dynamics.values.TargetValueDynamic;
+
+public class AutomaticValueDynamic extends TargetValueDynamic {
+
+ public AutomaticValueDynamic(AutomaticDynamicProperties properties, float currentValue) {
+ super(properties);
+ this.currentValue = currentValue;
+ this.targetValue = currentValue;
+ }
+
+ public void update(float delta) {
+ float distance = targetValue - currentValue;
+ currentValue += distance * Math.min(properties.getAgility() * delta, 1);
+ }
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java
new file mode 100644
index 0000000..820d200
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentQueuedPool.java
@@ -0,0 +1,25 @@
+package fr.radi3nt.maths.pool;
+
+import java.util.Deque;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+public abstract class ConcurrentQueuedPool implements ObjectPool {
+
+ protected final Deque queue = new ConcurrentLinkedDeque<>();
+
+ @Override
+ public T borrow() {
+ T object = queue.pollFirst();
+ if (object == null)
+ return create();
+
+ return object;
+ }
+
+ protected abstract T create();
+
+ @Override
+ public void free(T object) {
+ queue.addFirst(object);
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java
new file mode 100644
index 0000000..bed93b5
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ConcurrentVector3fPool.java
@@ -0,0 +1,22 @@
+package fr.radi3nt.maths.pool;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+
+public class ConcurrentVector3fPool extends ConcurrentQueuedPool {
+
+ public ConcurrentVector3fPool() {
+ }
+
+ public ConcurrentVector3fPool(int baseObjectAmount) {
+ for (int i = 0; i < baseObjectAmount; i++) {
+ queue.add(create());
+ }
+ }
+
+ @Override
+ protected Vector3f create() {
+ return new SimpleVector3f();
+ }
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java
new file mode 100644
index 0000000..94babe3
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListPool.java
@@ -0,0 +1,28 @@
+package fr.radi3nt.maths.pool;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class ListPool implements ObjectPool {
+
+ protected final List queue = new ArrayList<>();
+
+ @Override
+ public T borrow() {
+ if (queue.isEmpty())
+ return create();
+
+ T object = queue.remove(queue.size()-1);
+ if (object == null)
+ return create();
+
+ return object;
+ }
+
+ protected abstract T create();
+
+ @Override
+ public void free(T object) {
+ queue.add(object);
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java
new file mode 100644
index 0000000..9981c96
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/ListVector3fPool.java
@@ -0,0 +1,22 @@
+package fr.radi3nt.maths.pool;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+
+public class ListVector3fPool extends ListPool {
+
+ public ListVector3fPool() {
+ }
+
+ public ListVector3fPool(int baseObjectAmount) {
+ for (int i = 0; i < baseObjectAmount; i++) {
+ queue.add(create());
+ }
+ }
+
+ @Override
+ protected Vector3f create() {
+ return new SimpleVector3f();
+ }
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java
index f5796a8..2088153 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/QueuedPool.java
@@ -1,14 +1,15 @@
package fr.radi3nt.maths.pool;
-import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.ArrayDeque;
+import java.util.Deque;
public abstract class QueuedPool implements ObjectPool {
- protected final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>();
+ protected final Deque queue = new ArrayDeque<>();
@Override
public T borrow() {
- T object = queue.poll();
+ T object = queue.pollLast();
if (object == null)
return create();
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java
index 32d9811..18a9b95 100644
--- a/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/pool/WaitingVector3fPool.java
@@ -9,6 +9,7 @@ public WaitingVector3fPool(int baseObjectAmount) {
for (int i = 0; i < baseObjectAmount; i++) {
queue.add(create());
}
+ queue.notifyAll();
}
public Vector3f borrow() {
@@ -16,9 +17,9 @@ public Vector3f borrow() {
if (object == null)
while ((object = queue.poll()) == null) {
try {
- Thread.sleep(1);
+ queue.wait();
} catch (InterruptedException e) {
- throw new RuntimeException(e);
+ e.printStackTrace();
}
}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java
new file mode 100644
index 0000000..d202aeb
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/MTV.java
@@ -0,0 +1,22 @@
+package fr.radi3nt.maths.sat;
+
+import fr.radi3nt.maths.sat.components.SatAxis;
+
+public class MTV {
+
+ private final SatAxis smallest;
+ private final double overlap;
+
+ public MTV(SatAxis smallest, double overlap) {
+ this.smallest = smallest;
+ this.overlap = overlap;
+ }
+
+ public SatAxis getSmallest() {
+ return smallest;
+ }
+
+ public double getOverlap() {
+ return overlap;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java
new file mode 100644
index 0000000..ebc152e
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/AxisAndVertexIndex.java
@@ -0,0 +1,22 @@
+package fr.radi3nt.maths.sat.clip;
+
+import fr.radi3nt.maths.components.Vector3D;
+
+public class AxisAndVertexIndex {
+
+ private final Vector3D axis;
+ private final int index;
+
+ public AxisAndVertexIndex(Vector3D axis, int index) {
+ this.axis = axis;
+ this.index = index;
+ }
+
+ public Vector3D getAxis() {
+ return axis;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java
new file mode 100644
index 0000000..9d87f15
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlane.java
@@ -0,0 +1,47 @@
+package fr.radi3nt.maths.sat.clip;
+
+import fr.radi3nt.maths.components.Vector3D;
+
+public class ClipPlane {
+
+ private final Vector3D normal;
+ private final Vector3D vertexOnPlane;
+
+ public ClipPlane(Vector3D normal, Vector3D vertexOnPlane) {
+ this.normal = normal;
+ this.vertexOnPlane = vertexOnPlane;
+ }
+
+ public void clip(Edge[] otherEdges) {
+ double projectedClip = normal.dot(vertexOnPlane);
+
+ for (int i = 0; i < otherEdges.length; i++) {
+ Edge edge = otherEdges[i];
+ if (edge==null)
+ continue;
+
+ double projectedVertex1 = normal.dot(edge.getVertex1());
+ double projectedVertex2 = normal.dot(edge.getVertex2());
+
+ if (!(projectedVertex1 >= projectedClip) || !(projectedVertex2 >= projectedClip)) {
+ if (projectedVertex1 >= projectedClip) {
+ double on = (projectedClip - projectedVertex1) / (projectedVertex2 - projectedVertex1);
+ Vector3D computedNewVertex = computeInterpolation(edge.getVertex1(), edge.getVertex2(), on);
+ edge.setVertices(edge.getVertex1(), computedNewVertex);
+
+ } else if (projectedVertex2 >= projectedClip) {
+ double on = (projectedClip - projectedVertex2) / (projectedVertex1 - projectedVertex2);
+ Vector3D computedNewVertex = computeInterpolation(edge.getVertex2(), edge.getVertex1(), on);
+ edge.setVertices(computedNewVertex, edge.getVertex2());
+ } else {
+ otherEdges[i] = null;
+ }
+ }
+ }
+ }
+
+ private Vector3D computeInterpolation(Vector3D vertex1, Vector3D vertex2, double on) {
+ Vector3D edgeLocal = vertex2.clone().subtract(vertex1);
+ return vertex1.clone().add(edgeLocal.multiply(on));
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java
new file mode 100644
index 0000000..155b9b0
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/ClipPlanes.java
@@ -0,0 +1,41 @@
+package fr.radi3nt.maths.sat.clip;
+
+import fr.radi3nt.maths.components.Vector3D;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ClipPlanes {
+
+ private static final double EPSILON = 1e-2f;
+ private final ClipPlane[] clipPlane;
+
+ public ClipPlanes(ClipPlane... clipPlane) {
+ this.clipPlane = clipPlane;
+ }
+
+ public Edge[] clipEdges(Edge[] edges) {
+ for (ClipPlane plane : clipPlane) {
+ plane.clip(edges);
+ }
+ return edges;
+ }
+
+ public Collection clip(Edge[] edges) {
+ Edge[] edgeList = clipEdges(edges);
+ Collection result = new ArrayList<>(edgeList.length);
+ for (Edge edge : edgeList) {
+ if (edge==null)
+ continue;
+ result.add(edge.getVertex1());
+ if (notSameVertices(edge))
+ result.add(edge.getVertex2());
+ }
+ return result;
+ }
+
+ private static boolean notSameVertices(Edge edge) {
+ return edge.getVertex1().clone().subtract(edge.getVertex2()).lengthSquared() > EPSILON;
+ }
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java
new file mode 100644
index 0000000..ec9505a
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/clip/Edge.java
@@ -0,0 +1,28 @@
+package fr.radi3nt.maths.sat.clip;
+
+import fr.radi3nt.maths.components.Vector3D;
+
+public class Edge {
+
+ private Vector3D vertex1;
+ private Vector3D vertex2;
+
+ public Edge(Vector3D vertex1, Vector3D vertex2) {
+ this.vertex1 = vertex1;
+ this.vertex2 = vertex2;
+ }
+
+ public Vector3D getVertex1() {
+ return vertex1;
+ }
+
+ public Vector3D getVertex2() {
+ return vertex2;
+ }
+
+ public void setVertices(Vector3D vertex1, Vector3D vertex2) {
+ this.vertex1 = vertex1;
+ this.vertex2 = vertex2;
+ }
+
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java
new file mode 100644
index 0000000..888f03b
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatAxis.java
@@ -0,0 +1,32 @@
+package fr.radi3nt.maths.sat.components;
+
+import fr.radi3nt.maths.components.Vector3D;
+
+public class SatAxis {
+
+ private Vector3D normal;
+
+ public SatAxis(Vector3D normal) {
+ this.normal = normal;
+ }
+
+ public void set(Vector3D normal) {
+ this.normal = normal;
+ }
+
+ public double dot(Vector3D dotted) {
+ return normal.dot(dotted);
+ }
+
+ public Vector3D getNormal() {
+ return normal;
+ }
+
+ public SatAxis useNewNormalVector(Vector3D newNormal) {
+ newNormal.setX(this.normal.getX());
+ newNormal.setY(this.normal.getY());
+ newNormal.setZ(this.normal.getZ());
+ this.normal = newNormal;
+ return this;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java
new file mode 100644
index 0000000..9db35e6
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/components/SatEdge.java
@@ -0,0 +1,20 @@
+package fr.radi3nt.maths.sat.components;
+
+import fr.radi3nt.maths.components.Vector3D;
+
+public class SatEdge {
+
+ private final Vector3D edge;
+
+ public SatEdge(Vector3D edge) {
+ this.edge = edge;
+ }
+
+ public SatAxis axis(SatEdge other) {
+ return new SatAxis(other.edge.getCrossProduct(edge, new Vector3D()).normalize());
+ }
+
+ public SatAxis axis(SatEdge other, Vector3D result) {
+ return new SatAxis(other.edge.getCrossProduct(edge, result).normalize());
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java
new file mode 100644
index 0000000..190b806
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/NewSatProjectionManager.java
@@ -0,0 +1,13 @@
+package fr.radi3nt.maths.sat.projection;
+
+public class NewSatProjectionManager implements SatProjectionProvider {
+ @Override
+ public SatProjection project(double min, double max) {
+ return new SatProjection(min, max);
+ }
+
+ @Override
+ public SatProjectionProvider duplicate() {
+ return new NewSatProjectionManager();
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java
new file mode 100644
index 0000000..0d90628
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/OverlapInfo.java
@@ -0,0 +1,20 @@
+package fr.radi3nt.maths.sat.projection;
+
+public class OverlapInfo {
+
+ private final boolean overlap;
+ private final double overlapAmount;
+
+ public OverlapInfo(boolean overlap, double overlapAmount) {
+ this.overlap = overlap;
+ this.overlapAmount = overlapAmount;
+ }
+
+ public boolean isOverlap() {
+ return overlap;
+ }
+
+ public double getOverlapAmount() {
+ return overlapAmount;
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java
new file mode 100644
index 0000000..ab24ada
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/ReuseSatProjectionManager.java
@@ -0,0 +1,18 @@
+package fr.radi3nt.maths.sat.projection;
+
+public class ReuseSatProjectionManager implements SatProjectionProvider {
+
+ private final SatProjection satProjection = new SatProjection(0, 0);
+
+ @Override
+ public SatProjection project(double min, double max) {
+ satProjection.setMin(min);
+ satProjection.setMax(max);
+ return satProjection;
+ }
+
+ @Override
+ public SatProjectionProvider duplicate() {
+ return new ReuseSatProjectionManager();
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java
new file mode 100644
index 0000000..1a61c25
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjection.java
@@ -0,0 +1,112 @@
+package fr.radi3nt.maths.sat.projection;
+
+import static java.lang.Math.abs;
+
+public class SatProjection {
+
+ private static final OverlapInfo NO_OVERLAP = new OverlapInfo(false, 0);
+
+ public double min;
+ public double max;
+
+ private double tEnter;
+ private double tLeave;
+
+ public SatProjection(double min, double max) {
+ this.min = min;
+ this.max = max;
+ }
+
+ public OverlapInfo overlapInfo(SatProjection p2) {
+ if (this.min <= p2.min) {
+ if (this.max >= p2.min)
+ return new OverlapInfo(true, abs(p2.min - this.max));
+ } else {
+ if (this.min <= p2.max)
+ return new OverlapInfo(true, abs(this.min - p2.max));
+ }
+ return NO_OVERLAP;
+ }
+
+ public boolean contains(SatProjection p2) {
+ return (min <= p2.min && max >= p2.max);
+ }
+
+ public boolean noOverlap(SatProjection p2) {
+ return !overlap(p2);
+ }
+
+ public boolean overlap(SatProjection p2) {
+ return this.min <= p2.max ? this.max >= p2.min : this.min <= p2.min;
+ }
+
+ public boolean overlap(double p2) {
+ return this.min < p2 && this.max > p2;
+ }
+
+ public void sweptOverlap(SatProjection p2, double speed) {
+ double tEnter;
+ double tLeave;
+
+ tEnter = (p2.min - this.max) / speed;
+ tLeave = (p2.max - this.min) / speed;
+
+ if (tEnter > tLeave) {
+ double oldTEnter = tEnter;
+ tEnter = tLeave;
+ tLeave = oldTEnter;
+ }
+
+ this.tEnter = tEnter;
+ this.tLeave = tLeave;
+ }
+
+ public double getOverlap(SatProjection p2) {
+ if (this.min <= p2.min) {
+ if (this.max >= p2.min)
+ return p2.min - this.max;
+ } else {
+ if (p2.max >= this.min)
+ return this.min - p2.max;
+ }
+ return Double.MAX_VALUE;
+ }
+
+ public int getOverlapNormal(SatProjection p2) {
+ if (this.min <= p2.min) {
+ if (this.max >= p2.min)
+ return 1;
+ } else {
+ if (p2.max >= this.min)
+ return -1;
+ }
+ return 0;
+ }
+
+ public void setMin(double min) {
+ this.min = min;
+ }
+
+ public void setMax(double max) {
+ this.max = max;
+ }
+
+ public double getTEnter() {
+ return tEnter;
+ }
+
+ public double getTLeave() {
+ return tLeave;
+ }
+
+
+ @Override
+ public String toString() {
+ return "SatProjection{" +
+ "min=" + min +
+ ", max=" + max +
+ ", tEnter=" + tEnter +
+ ", tLeave=" + tLeave +
+ '}';
+ }
+}
diff --git a/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java
new file mode 100644
index 0000000..9555a00
--- /dev/null
+++ b/MathsHelper/src/main/java/fr/radi3nt/maths/sat/projection/SatProjectionProvider.java
@@ -0,0 +1,8 @@
+package fr.radi3nt.maths.sat.projection;
+
+public interface SatProjectionProvider {
+
+ SatProjection project(double min, double max);
+ SatProjectionProvider duplicate();
+
+}
diff --git a/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java
new file mode 100644
index 0000000..eff70ca
--- /dev/null
+++ b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/ArrayMatrixNxNdTest.java
@@ -0,0 +1,164 @@
+package fr.radi3nt.maths.components.arbitrary.matrix;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+class ArrayMatrixNxNdTest {
+
+ private static final ArrayMatrixNxNd resultOneRow = new ArrayMatrixNxNd(3, 4);
+ private static final ArrayMatrixNxNd resultMultiple = new ArrayMatrixNxNd(2, 3);
+
+ @BeforeAll
+ static void setUp() {
+ resultOneRow.set(0, 0, 1);
+ resultOneRow.set(0, 1, 2);
+ resultOneRow.set(0, 2, 3);
+ resultOneRow.set(0, 3, 4);
+
+ resultOneRow.set(1, 0, 2);
+ resultOneRow.set(1, 1, 4);
+ resultOneRow.set(1, 2, 6);
+ resultOneRow.set(1, 3, 8);
+
+ resultOneRow.set(2, 0, 3);
+ resultOneRow.set(2, 1, 6);
+ resultOneRow.set(2, 2, 9);
+ resultOneRow.set(2, 3, 12);
+
+ resultMultiple.set(0, 0, 22);
+ resultMultiple.set(1, 0, 28);
+
+ resultMultiple.set(0, 1, 49);
+ resultMultiple.set(1, 1, 64);
+
+ resultMultiple.set(0, 2, 76);
+ resultMultiple.set(1, 2, 100);
+ }
+
+ @Test
+ void multiplyOneRow() {
+ ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(1, 4);
+ arrayMatrixNxNd.set(0, 0, 1);
+ arrayMatrixNxNd.set(0, 1, 2);
+ arrayMatrixNxNd.set(0, 2, 3);
+ arrayMatrixNxNd.set(0, 3, 4);
+ ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(3, 1);
+ arrayMatrixNxNd1.set(0, 0, 1);
+ arrayMatrixNxNd1.set(1, 0, 2);
+ arrayMatrixNxNd1.set(2, 0, 3);
+ Assertions.assertEquals(arrayMatrixNxNd.multiply(arrayMatrixNxNd1), resultOneRow);
+ }
+
+ @Test
+ void multiplyMultiple() {
+ ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(3, 3);
+ arrayMatrixNxNd.set(0, 0, 1);
+ arrayMatrixNxNd.set(1, 0, 2);
+ arrayMatrixNxNd.set(2, 0, 3);
+
+ arrayMatrixNxNd.set(0, 1, 4);
+ arrayMatrixNxNd.set(1, 1, 5);
+ arrayMatrixNxNd.set(2, 1, 6);
+
+ arrayMatrixNxNd.set(0, 2, 7);
+ arrayMatrixNxNd.set(1, 2, 8);
+ arrayMatrixNxNd.set(2, 2, 9);
+
+ ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(2, 3);
+ arrayMatrixNxNd1.set(0, 0, 1);
+ arrayMatrixNxNd1.set(1, 0, 2);
+
+ arrayMatrixNxNd1.set(0, 1, 3);
+ arrayMatrixNxNd1.set(1, 1, 4);
+
+ arrayMatrixNxNd1.set(0, 2, 5);
+ arrayMatrixNxNd1.set(1, 2, 6);
+
+ Assertions.assertEquals(arrayMatrixNxNd.multiply(arrayMatrixNxNd1), resultMultiple);
+ }
+
+ @Test
+ void multiplyWithTransposedOneRow() {
+ ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(1, 4);
+ arrayMatrixNxNd.set(0, 0, 1);
+ arrayMatrixNxNd.set(0, 1, 2);
+ arrayMatrixNxNd.set(0, 2, 3);
+ arrayMatrixNxNd.set(0, 3, 4);
+ ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(1, 3);
+ arrayMatrixNxNd1.set(0, 0, 1);
+ arrayMatrixNxNd1.set(0, 1, 2);
+ arrayMatrixNxNd1.set(0, 2, 3);
+ Assertions.assertEquals(arrayMatrixNxNd.multiplyWithTransposed(arrayMatrixNxNd1), resultOneRow);
+ }
+
+ @Test
+ void multiplyWithTransposedMultiple() {
+ ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(3, 3);
+ arrayMatrixNxNd.set(0, 0, 1);
+ arrayMatrixNxNd.set(1, 0, 2);
+ arrayMatrixNxNd.set(2, 0, 3);
+
+ arrayMatrixNxNd.set(0, 1, 4);
+ arrayMatrixNxNd.set(1, 1, 5);
+ arrayMatrixNxNd.set(2, 1, 6);
+
+ arrayMatrixNxNd.set(0, 2, 7);
+ arrayMatrixNxNd.set(1, 2, 8);
+ arrayMatrixNxNd.set(2, 2, 9);
+
+ ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(3, 2);
+ arrayMatrixNxNd1.set(0, 0, 1);
+ arrayMatrixNxNd1.set(0, 1, 2);
+
+ arrayMatrixNxNd1.set(1, 0, 3);
+ arrayMatrixNxNd1.set(1, 1, 4);
+
+ arrayMatrixNxNd1.set(2, 0, 5);
+ arrayMatrixNxNd1.set(2, 1, 6);
+
+ Assertions.assertEquals(arrayMatrixNxNd.multiplyWithTransposed(arrayMatrixNxNd1), resultMultiple);
+ }
+
+ @Test
+ void multiplyWithTransposedOtherOneRow() {
+ ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(1, 4);
+ arrayMatrixNxNd.set(0, 0, 1);
+ arrayMatrixNxNd.set(0, 1, 2);
+ arrayMatrixNxNd.set(0, 2, 3);
+ arrayMatrixNxNd.set(0, 3, 4);
+ ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(1, 3);
+ arrayMatrixNxNd1.set(0, 0, 1);
+ arrayMatrixNxNd1.set(0, 1, 2);
+ arrayMatrixNxNd1.set(0, 2, 3);
+ Assertions.assertEquals(arrayMatrixNxNd1.multiplyTransposedOther(arrayMatrixNxNd), resultOneRow);
+ }
+
+ @Test
+ void multiplyWithTransposedOtherMultiple() {
+ ArrayMatrixNxNd arrayMatrixNxNd = new ArrayMatrixNxNd(3, 3);
+ arrayMatrixNxNd.set(0, 0, 1);
+ arrayMatrixNxNd.set(1, 0, 2);
+ arrayMatrixNxNd.set(2, 0, 3);
+
+ arrayMatrixNxNd.set(0, 1, 4);
+ arrayMatrixNxNd.set(1, 1, 5);
+ arrayMatrixNxNd.set(2, 1, 6);
+
+ arrayMatrixNxNd.set(0, 2, 7);
+ arrayMatrixNxNd.set(1, 2, 8);
+ arrayMatrixNxNd.set(2, 2, 9);
+
+ ArrayMatrixNxNd arrayMatrixNxNd1 = new ArrayMatrixNxNd(3, 2);
+ arrayMatrixNxNd1.set(0, 0, 1);
+ arrayMatrixNxNd1.set(0, 1, 2);
+
+ arrayMatrixNxNd1.set(1, 0, 3);
+ arrayMatrixNxNd1.set(1, 1, 4);
+
+ arrayMatrixNxNd1.set(2, 0, 5);
+ arrayMatrixNxNd1.set(2, 1, 6);
+ Assertions.assertEquals(arrayMatrixNxNd1.multiplyTransposedOther(arrayMatrixNxNd), resultMultiple);
+ }
+
+}
\ No newline at end of file
diff --git a/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java
new file mode 100644
index 0000000..5601aeb
--- /dev/null
+++ b/MathsHelper/src/test/java/fr/radi3nt/maths/components/arbitrary/matrix/sparse/SparseMatrixdTest.java
@@ -0,0 +1,22 @@
+package fr.radi3nt.maths.components.arbitrary.matrix.sparse;
+
+import org.junit.jupiter.api.Test;
+
+class SparseMatrixdTest {
+
+ @Test
+ void multiply() {
+ SparseMatrixd sparseMatrixd = new SparseMatrixd();
+ sparseMatrixd.add(new SparseBlockd(0, 0, 1, 1, new double[]{1}));
+ sparseMatrixd.add(new SparseBlockd(0, 1, 1, 1, new double[]{2}));
+ sparseMatrixd.add(new SparseBlockd(0, 2, 1, 1, new double[]{3}));
+ sparseMatrixd.add(new SparseBlockd(0, 3, 1, 1, new double[]{4}));
+
+ SparseMatrixd sparseMatrixd1 = new SparseMatrixd();
+ sparseMatrixd1.add(new SparseBlockd(0, 0, 1, 1, new double[]{1}));
+ sparseMatrixd1.add(new SparseBlockd(1, 0, 1, 1, new double[]{2}));
+ sparseMatrixd1.add(new SparseBlockd(2, 0, 1, 1, new double[]{3}));
+
+ System.out.println(sparseMatrixd.multiply(sparseMatrixd1));
+ }
+}
\ No newline at end of file
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java
index da474de..c3315f0 100644
--- a/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/SeededFastSimplexNoise.java
@@ -1,5 +1,7 @@
package fr.radi3nt.noise;
+import fr.radi3nt.noise.simplex.SimplexNoise;
+
import java.util.Random;
public class SeededFastSimplexNoise {
@@ -16,10 +18,10 @@ public SeededFastSimplexNoise(long seed) {
}
public double noise(double x, double y, double z) {
- return FastSimplexNoise.noise(x + xOffset, y + yOffset, z + zOffset);
+ return SimplexNoise.noise((float) (x + xOffset), (float) (y + yOffset), (float) (z + zOffset));
}
public double noise(double x, double z) {
- return FastSimplexNoise.noise(x + xOffset, z + zOffset);
+ return SimplexNoise.noise((float) (x + xOffset), (float) (z + zOffset));
}
}
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java
index 503ee4b..34daefb 100644
--- a/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/SimpleNoise3D.java
@@ -1,7 +1,4 @@
-package fr.radi3nt.noise.noise;
-
-import fr.radi3nt.noise.Noise3D;
-import fr.radi3nt.noise.SimplexNoise;
+package fr.radi3nt.noise;
public class SimpleNoise3D implements Noise3D {
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java
index 2bd34fc..5c84746 100644
--- a/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/TerrainHeight2D.java
@@ -1,7 +1,4 @@
-package fr.radi3nt.noise.noise;
-
-import fr.radi3nt.noise.Noise3D;
-import fr.radi3nt.noise.SimplexNoise;
+package fr.radi3nt.noise;
public class TerrainHeight2D implements Noise3D {
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java
new file mode 100644
index 0000000..aac5ed9
--- /dev/null
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/VaryingSeedNoise.java
@@ -0,0 +1,26 @@
+package fr.radi3nt.noise;
+
+import fr.radi3nt.noise.simplex.SimplexNoise;
+
+import java.util.Random;
+
+public class VaryingSeedNoise {
+
+ public static float noise(Random random, float x, float y, float z, float size) {
+ float xOffset = offsetBasedOnSeed(random);
+ float yOffset = offsetBasedOnSeed(random);
+ float zOffset = offsetBasedOnSeed(random);
+ return SimplexNoise.noise(xOffset+x/size, yOffset+y/size, zOffset+z/size);
+ }
+
+ public static float noise(Random random, float x, float y, float size) {
+ float xOffset = offsetBasedOnSeed(random);
+ float yOffset = offsetBasedOnSeed(random);
+ return SimplexNoise.noise(xOffset+x/size, yOffset+y/size);
+ }
+
+ private static float offsetBasedOnSeed(Random random) {
+ return random.nextFloat();
+ }
+
+}
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java
new file mode 100644
index 0000000..17fe6e6
--- /dev/null
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/DoubleNoise3D.java
@@ -0,0 +1,8 @@
+package fr.radi3nt.noise.generator;
+
+public interface DoubleNoise3D {
+
+ double noise(double x, double y, double z);
+ double noise(double x, double y, double z, double w);
+
+}
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java
new file mode 100644
index 0000000..0766435
--- /dev/null
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/generator/FastSimplexNoise3D.java
@@ -0,0 +1,37 @@
+package fr.radi3nt.noise.generator;
+
+import fr.radi3nt.noise.FastSimplexNoise;
+
+import java.util.Random;
+
+public class FastSimplexNoise3D implements DoubleNoise3D {
+
+ private final long seed;
+ private final double size;
+
+ private final double offsetX;
+ private final double offsetY;
+ private final double offsetZ;
+ private final double offsetW;
+
+ public FastSimplexNoise3D(long seed, double size) {
+ this.seed = seed;
+ this.size = size;
+
+ Random random = new Random(seed);
+ this.offsetX = random.nextDouble()*1024D-512D;
+ this.offsetY = random.nextDouble()*1024D-512D;
+ this.offsetZ = random.nextDouble()*1024D-512D;
+ this.offsetW = random.nextDouble()*1024D-512D;
+ }
+
+ @Override
+ public double noise(double x, double y, double z) {
+ return FastSimplexNoise.noise(x*size + offsetX, y*size+ offsetY, z*size+ offsetZ)*0.5d+0.5d;
+ }
+
+ @Override
+ public double noise(double x, double y, double z, double w) {
+ return FastSimplexNoise.noise(x*size + offsetX, y*size+ offsetY, z*size+ offsetZ, w*size+offsetW)*0.5d+0.5d;
+ }
+}
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java
new file mode 100644
index 0000000..fe48e8e
--- /dev/null
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SeededSimplexNoise.java
@@ -0,0 +1,30 @@
+package fr.radi3nt.noise.simplex;
+
+import java.util.Random;
+
+public class SeededSimplexNoise {
+
+ private final long seed;
+
+ private final float offsetX;
+ private final float offsetY;
+ private final float offsetZ;
+
+ public SeededSimplexNoise(long seed) {
+ this.seed = seed;
+ Random random = new Random(seed);
+ offsetX = (float) (random.nextDouble()*1024);
+ offsetY = (float) (random.nextDouble()*1024);
+ offsetZ = (float) (random.nextDouble()*1024);
+ }
+
+ public float noise(final float x, final float y) {
+ return SimplexNoise.noise(x+offsetX, y+offsetY);
+ }
+
+ public float noise(final float x, final float y, final float z) {
+ return SimplexNoise.noise(x+offsetX, y+offsetY, z+offsetZ);
+ }
+
+
+}
diff --git a/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java
new file mode 100644
index 0000000..0f1eb85
--- /dev/null
+++ b/NoiseHelper/src/main/java/fr/radi3nt/noise/simplex/SimplexNoise.java
@@ -0,0 +1,455 @@
+package fr.radi3nt.noise.simplex;
+
+public class SimplexNoise {
+
+ private static class Vector3b {
+ byte x, y, z;
+ Vector3b(int x, int y, int z) {
+ super();
+ this.x = (byte) x;
+ this.y = (byte) y;
+ this.z = (byte) z;
+ }
+ }
+ private static class Vector4b {
+ byte x, y, z, w;
+ Vector4b(int x, int y, int z, int w) {
+ super();
+ this.x = (byte) x;
+ this.y = (byte) y;
+ this.z = (byte) z;
+ this.w = (byte) w;
+ }
+ }
+
+ // Kai Burjack:
+ // Use a three-component vector here to save memory. (instead of using 4-component 'Grad' class)
+ // And as the original author mentioned on the 'Grad' class, using a class to store the gradient components
+ // is indeed faster compared to using a simple int[] array...
+ private static final Vector3b[] grad3 = { new Vector3b(1, 1, 0), new Vector3b(-1, 1, 0), new Vector3b(1, -1, 0), new Vector3b(-1, -1, 0),
+ new Vector3b(1, 0, 1), new Vector3b(-1, 0, 1), new Vector3b(1, 0, -1), new Vector3b(-1, 0, -1), new Vector3b(0, 1, 1), new Vector3b(0, -1, 1),
+ new Vector3b(0, 1, -1), new Vector3b(0, -1, -1) };
+
+ // Kai Burjack:
+ // As the original author mentioned on the 'Grad' class, using a class to store the gradient components
+ // is indeed faster compared to using a simple int[] array...
+ private static final Vector4b[] grad4 = { new Vector4b(0, 1, 1, 1), new Vector4b(0, 1, 1, -1), new Vector4b(0, 1, -1, 1), new Vector4b(0, 1, -1, -1),
+ new Vector4b(0, -1, 1, 1), new Vector4b(0, -1, 1, -1), new Vector4b(0, -1, -1, 1), new Vector4b(0, -1, -1, -1), new Vector4b(1, 0, 1, 1),
+ new Vector4b(1, 0, 1, -1), new Vector4b(1, 0, -1, 1), new Vector4b(1, 0, -1, -1), new Vector4b(-1, 0, 1, 1), new Vector4b(-1, 0, 1, -1),
+ new Vector4b(-1, 0, -1, 1), new Vector4b(-1, 0, -1, -1), new Vector4b(1, 1, 0, 1), new Vector4b(1, 1, 0, -1), new Vector4b(1, -1, 0, 1),
+ new Vector4b(1, -1, 0, -1), new Vector4b(-1, 1, 0, 1), new Vector4b(-1, 1, 0, -1), new Vector4b(-1, -1, 0, 1), new Vector4b(-1, -1, 0, -1),
+ new Vector4b(1, 1, 1, 0), new Vector4b(1, 1, -1, 0), new Vector4b(1, -1, 1, 0), new Vector4b(1, -1, -1, 0), new Vector4b(-1, 1, 1, 0),
+ new Vector4b(-1, 1, -1, 0), new Vector4b(-1, -1, 1, 0), new Vector4b(-1, -1, -1, 0) };
+
+ // Kai Burjack:
+ // Use a byte[] instead of a short[] to save memory
+ private static final byte[] p = { -105, -96, -119, 91, 90, 15, -125, 13, -55, 95, 96, 53, -62, -23, 7, -31, -116, 36, 103, 30, 69, -114, 8, 99, 37, -16,
+ 21, 10, 23, -66, 6, -108, -9, 120, -22, 75, 0, 26, -59, 62, 94, -4, -37, -53, 117, 35, 11, 32, 57, -79, 33, 88, -19, -107, 56, 87, -82, 20, 125,
+ -120, -85, -88, 68, -81, 74, -91, 71, -122, -117, 48, 27, -90, 77, -110, -98, -25, 83, 111, -27, 122, 60, -45, -123, -26, -36, 105, 92, 41, 55, 46,
+ -11, 40, -12, 102, -113, 54, 65, 25, 63, -95, 1, -40, 80, 73, -47, 76, -124, -69, -48, 89, 18, -87, -56, -60, -121, -126, 116, -68, -97, 86, -92,
+ 100, 109, -58, -83, -70, 3, 64, 52, -39, -30, -6, 124, 123, 5, -54, 38, -109, 118, 126, -1, 82, 85, -44, -49, -50, 59, -29, 47, 16, 58, 17, -74,
+ -67, 28, 42, -33, -73, -86, -43, 119, -8, -104, 2, 44, -102, -93, 70, -35, -103, 101, -101, -89, 43, -84, 9, -127, 22, 39, -3, 19, 98, 108, 110,
+ 79, 113, -32, -24, -78, -71, 112, 104, -38, -10, 97, -28, -5, 34, -14, -63, -18, -46, -112, 12, -65, -77, -94, -15, 81, 51, -111, -21, -7, 14, -17,
+ 107, 49, -64, -42, 31, -75, -57, 106, -99, -72, 84, -52, -80, 115, 121, 50, 45, 127, 4, -106, -2, -118, -20, -51, 93, -34, 114, 67, 29, 24, 72,
+ -13, -115, -128, -61, 78, 66, -41, 61, -100, -76 };
+ // To remove the need for index wrapping, float the permutation table length
+ private static final byte[] perm = new byte[512];
+ private static final byte[] permMod12 = new byte[512];
+ static {
+ for (int i = 0; i < 512; i++) {
+ perm[i] = p[i & 255];
+ permMod12[i] = (byte) ((perm[i]&0xFF) % 12);
+ }
+ }
+
+ // Skewing and unskewing factors for 2, 3, and 4 dimensions
+ private static final float F2 = 0.3660254037844386f; // <- (float) (0.5f * (Math.sqrt(3.0f) - 1.0f));
+ private static final float G2 = 0.21132486540518713f; // <- (float) ((3.0f - Math.sqrt(3.0f)) / 6.0f);
+ private static final float F3 = 1.0f / 3.0f;
+ private static final float G3 = 1.0f / 6.0f;
+ private static final float F4 = 0.30901699437494745f; // <- (float) ((Math.sqrt(5.0f) - 1.0f) / 4.0f);
+ private static final float G4 = 0.1381966011250105f; // <- (float) ((5.0f - Math.sqrt(5.0f)) / 20.0f);
+
+ // This method is a *lot* faster than using (int)Math.floor(x)
+ private static int fastfloor(float x) {
+ int xi = (int) x;
+ return x < xi ? xi - 1 : xi;
+ }
+
+ private static float dot(Vector3b g, float x, float y) {
+ return g.x * x + g.y * y;
+ }
+
+ private static float dot(Vector3b g, float x, float y, float z) {
+ return g.x * x + g.y * y + g.z * z;
+ }
+
+ private static float dot(Vector4b g, float x, float y, float z, float w) {
+ return g.x * x + g.y * y + g.z * z + g.w * w;
+ }
+
+ /**
+ * Compute 2D simplex noise for the given input vector (x, y)
.
+ *
+ * The result is in the range [-1..+1]
.
+ *
+ * @param x
+ * the x coordinate
+ * @param y
+ * the y coordinate
+ * @return the noise value (within [-1..+1]
)
+ */
+ public static float noise(float x, float y) {
+ float n0, n1, n2; // Noise contributions from the three corners
+ // Skew the input space to determine which simplex cell we're in
+ float s = (x + y) * F2; // Hairy factor for 2D
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ float t = (i + j) * G2;
+ float X0 = i - t; // Unskew the cell origin back to (x,y) space
+ float Y0 = j - t;
+ float x0 = x - X0; // The x,y distances from the cell origin
+ float y0 = y - Y0;
+ // For the 2D case, the simplex shape is an equilateral triangle.
+ // Determine which simplex we are in.
+ int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
+ if (x0 > y0) {
+ i1 = 1;
+ j1 = 0;
+ } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
+ else {
+ i1 = 0;
+ j1 = 1;
+ } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
+ // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
+ // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
+ // c = (3-sqrt(3))/6
+ float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
+ float y1 = y0 - j1 + G2;
+ float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
+ float y2 = y0 - 1.0f + 2.0f * G2;
+ // Work out the hashed gradient indices of the three simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+ int gi0 = permMod12[ii + perm[jj]&0xFF]&0xFF;
+ int gi1 = permMod12[ii + i1 + perm[jj + j1]&0xFF]&0xFF;
+ int gi2 = permMod12[ii + 1 + perm[jj + 1]&0xFF]&0xFF;
+ // Calculate the contribution from the three corners
+ float t0 = 0.5f - x0 * x0 - y0 * y0;
+ if (t0 < 0.0f)
+ n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient
+ }
+ float t1 = 0.5f - x1 * x1 - y1 * y1;
+ if (t1 < 0.0f)
+ n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad3[gi1], x1, y1);
+ }
+ float t2 = 0.5f - x2 * x2 - y2 * y2;
+ if (t2 < 0.0f)
+ n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad3[gi2], x2, y2);
+ }
+ // Add contributions from each corner to get the final noise value.
+ // The result is scaled to return values in the interval [-1,1].
+ return 70.0f * (n0 + n1 + n2);
+ }
+
+ /**
+ * Compute 3D simplex noise for the given input vector (x, y, z)
.
+ *
+ * The result is in the range [-1..+1]
.
+ *
+ * @param x
+ * the x coordinate
+ * @param y
+ * the y coordinate
+ * @param z
+ * the z coordinate
+ * @return the noise value (within [-1..+1]
)
+ */
+ public static float noise(float x, float y, float z) {
+ float n0, n1, n2, n3; // Noise contributions from the four corners
+ // Skew the input space to determine which simplex cell we're in
+ float s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ int k = fastfloor(z + s);
+ float t = (i + j + k) * G3;
+ float X0 = i - t; // Unskew the cell origin back to (x,y,z) space
+ float Y0 = j - t;
+ float Z0 = k - t;
+ float x0 = x - X0; // The x,y,z distances from the cell origin
+ float y0 = y - Y0;
+ float z0 = z - Z0;
+ // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
+ // Determine which simplex we are in.
+ int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
+ int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
+ if (x0 >= y0) {
+ if (y0 >= z0) {
+ i1 = 1;
+ j1 = 0;
+ k1 = 0;
+ i2 = 1;
+ j2 = 1;
+ k2 = 0;
+ } // X Y Z order
+ else if (x0 >= z0) {
+ i1 = 1;
+ j1 = 0;
+ k1 = 0;
+ i2 = 1;
+ j2 = 0;
+ k2 = 1;
+ } // X Z Y order
+ else {
+ i1 = 0;
+ j1 = 0;
+ k1 = 1;
+ i2 = 1;
+ j2 = 0;
+ k2 = 1;
+ } // Z X Y order
+ } else { // x0(x, y, z, w).
+ *
+ * The result is in the range [-1..+1]
.
+ *
+ * @param x
+ * the x coordinate
+ * @param y
+ * the y coordinate
+ * @param z
+ * the z coordinate
+ * @param w
+ * the w coordinate
+ * @return the noise value (within [-1..+1]
)
+ */
+ public static float noise(float x, float y, float z, float w) {
+ float n0, n1, n2, n3, n4; // Noise contributions from the five corners
+ // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
+ float s = (x + y + z + w) * F4; // Factor for 4D skewing
+ int i = fastfloor(x + s);
+ int j = fastfloor(y + s);
+ int k = fastfloor(z + s);
+ int l = fastfloor(w + s);
+ float t = (i + j + k + l) * G4; // Factor for 4D unskewing
+ float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
+ float Y0 = j - t;
+ float Z0 = k - t;
+ float W0 = l - t;
+ float x0 = x - X0; // The x,y,z,w distances from the cell origin
+ float y0 = y - Y0;
+ float z0 = z - Z0;
+ float w0 = w - W0;
+ // For the 4D case, the simplex is a 4D shape I won't even try to describe.
+ // To find out which of the 24 possible simplices we're in, we need to
+ // determine the magnitude ordering of x0, y0, z0 and w0.
+ // Six pair-wise comparisons are performed between each possible pair
+ // of the four coordinates, and the results are used to rank the numbers.
+ int rankx = 0;
+ int ranky = 0;
+ int rankz = 0;
+ int rankw = 0;
+ if (x0 > y0)
+ rankx++;
+ else
+ ranky++;
+ if (x0 > z0)
+ rankx++;
+ else
+ rankz++;
+ if (x0 > w0)
+ rankx++;
+ else
+ rankw++;
+ if (y0 > z0)
+ ranky++;
+ else
+ rankz++;
+ if (y0 > w0)
+ ranky++;
+ else
+ rankw++;
+ if (z0 > w0)
+ rankz++;
+ else
+ rankw++;
+ int i1, j1, k1, l1; // The integer offsets for the second simplex corner
+ int i2, j2, k2, l2; // The integer offsets for the third simplex corner
+ int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
+ // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
+ // Many values of c will never occur, since e.g. x>y>z>w makes x= 3 ? 1 : 0;
+ j1 = ranky >= 3 ? 1 : 0;
+ k1 = rankz >= 3 ? 1 : 0;
+ l1 = rankw >= 3 ? 1 : 0;
+ // Rank 2 denotes the second largest coordinate.
+ i2 = rankx >= 2 ? 1 : 0;
+ j2 = ranky >= 2 ? 1 : 0;
+ k2 = rankz >= 2 ? 1 : 0;
+ l2 = rankw >= 2 ? 1 : 0;
+ // Rank 1 denotes the second smallest coordinate.
+ i3 = rankx >= 1 ? 1 : 0;
+ j3 = ranky >= 1 ? 1 : 0;
+ k3 = rankz >= 1 ? 1 : 0;
+ l3 = rankw >= 1 ? 1 : 0;
+ // The fifth corner has all coordinate offsets = 1, so no need to compute that.
+ float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
+ float y1 = y0 - j1 + G4;
+ float z1 = z0 - k1 + G4;
+ float w1 = w0 - l1 + G4;
+ float x2 = x0 - i2 + 2.0f * G4; // Offsets for third corner in (x,y,z,w) coords
+ float y2 = y0 - j2 + 2.0f * G4;
+ float z2 = z0 - k2 + 2.0f * G4;
+ float w2 = w0 - l2 + 2.0f * G4;
+ float x3 = x0 - i3 + 3.0f * G4; // Offsets for fourth corner in (x,y,z,w) coords
+ float y3 = y0 - j3 + 3.0f * G4;
+ float z3 = z0 - k3 + 3.0f * G4;
+ float w3 = w0 - l3 + 3.0f * G4;
+ float x4 = x0 - 1.0f + 4.0f * G4; // Offsets for last corner in (x,y,z,w) coords
+ float y4 = y0 - 1.0f + 4.0f * G4;
+ float z4 = z0 - 1.0f + 4.0f * G4;
+ float w4 = w0 - 1.0f + 4.0f * G4;
+ // Work out the hashed gradient indices of the five simplex corners
+ int ii = i & 255;
+ int jj = j & 255;
+ int kk = k & 255;
+ int ll = l & 255;
+ int gi0 = (perm[ii + perm[jj + perm[kk + perm[ll]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi1 = (perm[ii + i1 + perm[jj + j1 + perm[kk + k1 + perm[ll + l1]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi2 = (perm[ii + i2 + perm[jj + j2 + perm[kk + k2 + perm[ll + l2]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi3 = (perm[ii + i3 + perm[jj + j3 + perm[kk + k3 + perm[ll + l3]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ int gi4 = (perm[ii + 1 + perm[jj + 1 + perm[kk + 1 + perm[ll + 1]&0xFF]&0xFF]&0xFF]&0xFF) % 32;
+ // Calculate the contribution from the five corners
+ float t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0 - w0 * w0;
+ if (t0 < 0.0f)
+ n0 = 0.0f;
+ else {
+ t0 *= t0;
+ n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0);
+ }
+ float t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1 - w1 * w1;
+ if (t1 < 0.0f)
+ n1 = 0.0f;
+ else {
+ t1 *= t1;
+ n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1);
+ }
+ float t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2 - w2 * w2;
+ if (t2 < 0.0f)
+ n2 = 0.0f;
+ else {
+ t2 *= t2;
+ n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2);
+ }
+ float t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3 - w3 * w3;
+ if (t3 < 0.0f)
+ n3 = 0.0f;
+ else {
+ t3 *= t3;
+ n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3);
+ }
+ float t4 = 0.6f - x4 * x4 - y4 * y4 - z4 * z4 - w4 * w4;
+ if (t4 < 0.0f)
+ n4 = 0.0f;
+ else {
+ t4 *= t4;
+ n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4);
+ }
+ // Sum up and scale the result to cover the range [-1,1]
+ return 27.0f * (n0 + n1 + n2 + n3 + n4);
+ }
+
+}
\ No newline at end of file
diff --git a/Pathfinding/pom.xml b/Pathfinding/pom.xml
new file mode 100644
index 0000000..fe8847b
--- /dev/null
+++ b/Pathfinding/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+ fr.radi3nt
+ JavaUtil
+ 1.0
+
+
+ Pathfinding
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+ fr.radi3nt
+ MathsHelper
+ 1.0
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java
new file mode 100644
index 0000000..7781142
--- /dev/null
+++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/AStarPathfinder.java
@@ -0,0 +1,129 @@
+package fr.radi3nt.pathfinding;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.pathfinding.heuristic.HeuristicEvaluator;
+import fr.radi3nt.pathfinding.node.*;
+import fr.radi3nt.pathfinding.path.IndexedPath;
+import fr.radi3nt.pathfinding.path.Path;
+import fr.radi3nt.pathfinding.path.optimisation.PathOptimiser;
+import fr.radi3nt.pathfinding.tracking.Neighbour;
+import fr.radi3nt.pathfinding.tracking.queue.PathPointQueue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class AStarPathfinder {
+
+ private static final int MAX_ITERATIONS = 100_000;
+ private final PathPointQueue pathQueue;
+ private final PathfinderPointSupplier pathfinderPointSupplier;
+ private final HeuristicEvaluator heuristicEvaluator;
+ private final Collection pathOptimisers;
+ private final float reachThreshold;
+ private final float pathfindingLimit;
+
+ public AStarPathfinder(PathPointQueue pathBuilder, PathfinderPointSupplier pathfinderPointSupplier, HeuristicEvaluator distanceCalculator, Collection pathOptimisers, float reachThreshold, float pathfindingLimit) {
+ this.pathQueue = pathBuilder;
+ this.pathfinderPointSupplier = pathfinderPointSupplier;
+ this.heuristicEvaluator = distanceCalculator;
+ this.pathOptimisers = pathOptimisers;
+ this.reachThreshold = reachThreshold;
+ this.pathfindingLimit = pathfindingLimit;
+ }
+
+ public Path find(Vector3f start, Vector3f end) {
+ pathQueue.clear();
+ pathfinderPointSupplier.prepare();
+
+ FindNode startPoint = pathfinderPointSupplier.pointFromPosition(start);
+ if (isEnd(end, startPoint))
+ return new IndexedPath(new PathNode[0]);
+
+ FindNode lastPoint = startPoint;
+ float lastDistanceToEnd = heuristicEvaluator.distanceBetween(startPoint.getFloatPosition(), end);
+ startPoint.set(0, 0, lastDistanceToEnd);
+
+ pathQueue.queue(startPoint);
+
+ boolean endFound = false;
+
+ int iterations = 0;
+ while (pathQueue.hasPoints() && !endFound && iterations= pathfindingLimit)
+ continue;
+
+ boolean opened = neighbourPoint.getStatus()== NodeStatus.OPENED;
+ if (opened && neighbourCostData.accumulatedCostFromStart pathNodes = new ArrayList<>();
+
+ FindNode current = lastPoint;
+ while (current!=null) {
+ pathNodes.add(pathfinderPointSupplier.nodeForPoint(current));
+ current = current.getPrevious();
+ }
+
+ Collections.reverse(pathNodes);
+
+ for (PathOptimiser pathOptimiser : pathOptimisers) {
+ pathNodes = pathOptimiser.optimise(pathNodes);
+ }
+
+ return new IndexedPath(pathNodes.toArray(new PathNode[0]));
+ }
+
+ private boolean isEnd(Vector3f end, FindNode current) {
+ return current.getFloatPosition().duplicate().sub(end).lengthSquared() {
+
+ private final Vector3i position;
+ private final CostData costData;
+ private FindNode previous;
+ private NodeStatus nodeStatus = NodeStatus.UNDISCOVERED;
+
+ public FindNode(Vector3i position, float weight) {
+ this.position = position;
+ this.costData = new CostData(weight);
+ }
+
+ public void open() {
+ nodeStatus = NodeStatus.OPENED;
+ }
+
+ public void visit() {
+ nodeStatus = NodeStatus.VISITED;
+ }
+
+ public NodeStatus getStatus() {
+ return nodeStatus;
+ }
+
+ public void set(float distanceFromStart, float accumulatedCostFromStart, float distanceFromEnd) {
+ costData.set(distanceFromStart, accumulatedCostFromStart, distanceFromEnd);
+ }
+
+ public void set(float distanceFromStart, float accumulatedCostFromStart, float distanceFromEnd, FindNode previous) {
+ set(distanceFromStart, accumulatedCostFromStart, distanceFromEnd);
+ this.previous = previous;
+ }
+
+ public boolean isCurrentPathFaster(float accumulatedOther) {
+ return costData.accumulatedCostFromStart optimise(List pathNodes);
+
+}
diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java
new file mode 100644
index 0000000..b04e174
--- /dev/null
+++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPathOptimiser.java
@@ -0,0 +1,65 @@
+package fr.radi3nt.pathfinding.path.optimisation;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.pathfinding.node.PathNode;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class SimplifyPathOptimiser implements PathOptimiser {
+
+ private final Collection simplifyPredicates;
+
+ public SimplifyPathOptimiser(Collection simplifyPredicates) {
+ this.simplifyPredicates = simplifyPredicates;
+ }
+
+ public SimplifyPathOptimiser(SimplifyPredicate... simplifyPredicates) {
+ this(new ArrayList<>(Arrays.asList(simplifyPredicates)));
+ }
+
+ @Override
+ public List optimise(List pathNodes) {
+ List result = new ArrayList<>();
+ PathNode lastNode = pathNodes.get(0);
+ Vector3f lastDirection = null;
+
+ result.add(pathNodes.get(0));
+
+ for (int i = 1; i < pathNodes.size()-1; i++) {
+ PathNode currentNode = pathNodes.get(i);
+ PathNode nextNode = pathNodes.get(i+1);
+ Vector3f currentPos = currentNode.getPosition();
+ Vector3f nextPos = nextNode.getPosition();
+
+ if (lastDirection==null) {
+ lastDirection = currentPos.duplicate().sub(lastNode.getPosition());
+ lastDirection.normalize();
+ }
+
+ Vector3f directionToNext = nextPos.duplicate().sub(currentPos);
+ directionToNext.normalize();
+
+ if (canSimplify(directionToNext, lastDirection, lastNode, currentNode, nextNode))
+ continue;
+
+ result.add(currentNode);
+ lastNode = currentNode;
+ lastDirection = null;
+ }
+
+ result.add(pathNodes.get(pathNodes.size()-1));
+
+ return result;
+ }
+
+ protected boolean canSimplify(Vector3f directionToNext, Vector3f lastDirection, PathNode lastPos, PathNode currentPos, PathNode nextPos) {
+ for (SimplifyPredicate simplifyPredicate : simplifyPredicates) {
+ if (simplifyPredicate.canSimplify(directionToNext, lastDirection, lastPos, currentPos, nextPos))
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java
new file mode 100644
index 0000000..dc00c07
--- /dev/null
+++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/SimplifyPredicate.java
@@ -0,0 +1,10 @@
+package fr.radi3nt.pathfinding.path.optimisation;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.pathfinding.node.PathNode;
+
+public interface SimplifyPredicate {
+
+ boolean canSimplify(Vector3f directionToNext, Vector3f lastDirection, PathNode lastPos, PathNode currentPos, PathNode nextPos);
+
+}
diff --git a/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java
new file mode 100644
index 0000000..158e788
--- /dev/null
+++ b/Pathfinding/src/main/java/fr/radi3nt/pathfinding/path/optimisation/StraightLineSimplification.java
@@ -0,0 +1,18 @@
+package fr.radi3nt.pathfinding.path.optimisation;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.pathfinding.node.PathNode;
+
+public class StraightLineSimplification implements SimplifyPredicate {
+
+ private final float threshold;
+
+ public StraightLineSimplification(float threshold) {
+ this.threshold = threshold;
+ }
+
+ @Override
+ public boolean canSimplify(Vector3f directionToNext, Vector3f lastDirection, PathNode lastPos, PathNode currentPos, PathNode nextPos) {
+ return directionToNext.duplicate().sub(lastDirection).lengthSquared() finderPoints = new PriorityQueue<>();
+
+ @Override
+ public FindNode dequeue() {
+ return finderPoints.poll();
+ }
+
+ @Override
+ public void queue(FindNode finderPoint) {
+ finderPoints.add(finderPoint);
+ }
+
+ @Override
+ public boolean hasPoints() {
+ return !finderPoints.isEmpty();
+ }
+
+ @Override
+ public void clear() {
+ finderPoints.clear();
+ }
+
+ @Override
+ public void update(FindNode neighbour) {
+ finderPoints.remove(neighbour);
+ finderPoints.add(neighbour);
+ }
+}
diff --git a/SplineHelper/.gitignore b/SplineHelper/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/SplineHelper/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/SplineHelper/pom.xml b/SplineHelper/pom.xml
new file mode 100644
index 0000000..dbfc846
--- /dev/null
+++ b/SplineHelper/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+ fr.radi3nt
+ JavaUtil
+ 1.0
+
+
+ SplineHelper
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+ fr.radi3nt
+ MathsHelper
+ 1.0
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java b/SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java
new file mode 100644
index 0000000..6a98521
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/MainSplineTesting.java
@@ -0,0 +1,36 @@
+package fr.radi3nt.spline;
+
+import fr.radi3nt.spline.curve.Curve;
+import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurve;
+import fr.radi3nt.spline.curve.curves.cardinal.CatmullRomCurve;
+import fr.radi3nt.spline.splines.Spline;
+import fr.radi3nt.spline.splines.builder.cardinal.dim1.DirectCardinalCurveController;
+
+public class MainSplineTesting {
+
+ public static void main(String[] args) {
+ //testCurves();
+ }
+
+ private static void printSpline(Spline spline, int times) {
+ for (int i = 0; i <= 10*times; i++) {
+ System.out.println(spline.interpolate(i / 10f));
+ }
+ System.out.println("--");
+ }
+
+ private static void testCurves() {
+ Curve curve = new CardinalCurve(new DirectCardinalCurveController(0, 1, 2, 3, 0.5f));
+ printCurve(curve, 0);
+ curve = new CatmullRomCurve(0, 1, 2, 3);
+ printCurve(curve, 1);
+ }
+
+ private static void printCurve(Curve curve, int index) {
+ for (int i = 0; i <= 10; i++) {
+ System.out.println(curve.interpolate(i / 10f+index));
+ }
+ System.out.println("--");
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java
new file mode 100644
index 0000000..a7b57a4
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/CharacteristicCurve.java
@@ -0,0 +1,19 @@
+package fr.radi3nt.spline.curve;
+
+public abstract class CharacteristicCurve implements Curve {
+
+ @Override
+ public float interpolate(float t) {
+ float t2 = t*t;
+ float t3 = t*t*t;
+ return computeP(1, t, t2, t3);
+ }
+
+ @Override
+ public float velocity(float t) {
+ float t2 = t*t;
+ return computeP(0, 1, 2*t, 3*t2);
+ }
+
+ protected abstract float computeP(float a, float t, float t2, float t3);
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java
new file mode 100644
index 0000000..d85b060
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/Curve.java
@@ -0,0 +1,8 @@
+package fr.radi3nt.spline.curve;
+
+public interface Curve {
+
+ float interpolate(float t);
+ float velocity(float t);
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java
new file mode 100644
index 0000000..7f87ec7
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/controller/CurveController.java
@@ -0,0 +1,7 @@
+package fr.radi3nt.spline.curve.controller;
+
+public interface CurveController {
+
+
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java
new file mode 100644
index 0000000..c5522ca
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/HermiteCurve.java
@@ -0,0 +1,32 @@
+package fr.radi3nt.spline.curve.curves;
+
+import fr.radi3nt.spline.curve.CharacteristicCurve;
+import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve;
+import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController;
+
+public class HermiteCurve extends CharacteristicCurve {
+
+ private final float startPoint;
+ private final float endPoint;
+
+ private final float velocityStart;
+ private final float velocityEnd;
+
+ public HermiteCurve(float startPoint, float endPoint, float velocityStart, float velocityEnd) {
+ this.startPoint = startPoint;
+ this.endPoint = endPoint;
+ this.velocityStart = velocityStart;
+ this.velocityEnd = velocityEnd;
+ }
+
+ public CubicBezierCurve toBezier() {
+ return new CubicBezierCurve(new DirectCubicBezierCurveController(startPoint, endPoint, startPoint+velocityStart/3, endPoint-velocityEnd/3));
+ }
+
+ protected float computeP(float a, float t, float t2, float t3) {
+ return a * startPoint
+ + t * (velocityStart)
+ + t2 * (-3*startPoint - 2*velocityStart + 3*endPoint - velocityEnd)
+ + t3 * (2*startPoint + velocityStart - 2*endPoint + velocityEnd);
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java
new file mode 100644
index 0000000..f1da16b
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurve.java
@@ -0,0 +1,29 @@
+package fr.radi3nt.spline.curve.curves.bcurve;
+
+import fr.radi3nt.spline.curve.CharacteristicCurve;
+
+public class BCurve extends CharacteristicCurve {
+
+ private final BCurveController controller;
+
+ public BCurve(BCurveController controller) {
+ this.controller = controller;
+ }
+
+ @Override
+ protected float computeP(float a, float t, float t2, float t3) {
+ float pointA = controller.getPositionA();
+ float pointB = controller.getPositionB();
+ float pointC = controller.getPositionC();
+ float pointD = controller.getPositionD();
+ float p = a * (pointA + 4*pointB + pointC)
+ + t *(-3*pointA + 3*pointC)
+ + t2 *(3*pointA - 6*pointB + 3*pointC)
+ + t3 *(-pointA + 3*pointB - 3*pointC + pointD);
+ return p/6;
+ }
+
+ public BCurveController getController() {
+ return controller;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java
new file mode 100644
index 0000000..bfced96
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bcurve/BCurveController.java
@@ -0,0 +1,12 @@
+package fr.radi3nt.spline.curve.curves.bcurve;
+
+import fr.radi3nt.spline.curve.controller.CurveController;
+
+public interface BCurveController extends CurveController {
+
+ float getPositionA();
+ float getPositionB();
+ float getPositionC();
+ float getPositionD();
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java
new file mode 100644
index 0000000..97a94b4
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurve.java
@@ -0,0 +1,30 @@
+package fr.radi3nt.spline.curve.curves.bezier;
+
+import fr.radi3nt.spline.curve.CharacteristicCurve;
+
+public class CubicBezierCurve extends CharacteristicCurve {
+
+ private final CubicBezierCurveController controller;
+
+ public CubicBezierCurve(CubicBezierCurveController controller) {
+ this.controller = controller;
+ }
+
+ protected float computeP(float a, float t, float t2, float t3) {
+
+ float startPoint = controller.getStartPoint();
+ float startPointControl = controller.getStartPointControl();
+
+ float endPoint = controller.getEndPoint();
+ float endPointControl = controller.getEndPointControl();
+
+ return a * startPoint
+ + t *(-3*startPoint+3*startPointControl)
+ + t2 *(3*startPoint-6*startPointControl+3*endPointControl)
+ + t3 *(-startPoint+3*startPointControl-3*endPointControl+endPoint);
+ }
+
+ public CubicBezierCurveController getController() {
+ return controller;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurveController.java
new file mode 100644
index 0000000..82fd6e8
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/bezier/CubicBezierCurveController.java
@@ -0,0 +1,11 @@
+package fr.radi3nt.spline.curve.curves.bezier;
+
+public interface CubicBezierCurveController {
+
+ float getStartPoint();
+ float getStartPointControl();
+
+ float getEndPoint();
+ float getEndPointControl();
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java
new file mode 100644
index 0000000..6bdd66d
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurve.java
@@ -0,0 +1,27 @@
+package fr.radi3nt.spline.curve.curves.cardinal;
+
+import fr.radi3nt.spline.curve.CharacteristicCurve;
+
+public class CardinalCurve extends CharacteristicCurve {
+
+ private final CardinalCurveController cardinalCurveController;
+
+ public CardinalCurve(CardinalCurveController cardinalCurveController) {
+ this.cardinalCurveController = cardinalCurveController;
+ }
+
+ @Override
+ protected float computeP(float a, float t, float t2, float t3) {
+
+ float pointA = cardinalCurveController.getPositionA();
+ float pointB = cardinalCurveController.getPositionB();
+ float pointC = cardinalCurveController.getPositionC();
+ float pointD = cardinalCurveController.getPositionD();
+ float scale = cardinalCurveController.getScale();
+
+ return a * pointB
+ + t *(-pointA*scale + pointC*scale)
+ + t2 *(2*pointA*scale + (scale-3)*pointB + (3-2*scale)*pointC - pointD*scale)
+ + t3 *(-pointA*scale + (2-scale)*pointB + (scale-2)*pointC + pointD*scale);
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java
new file mode 100644
index 0000000..1cc3239
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CardinalCurveController.java
@@ -0,0 +1,14 @@
+package fr.radi3nt.spline.curve.curves.cardinal;
+
+import fr.radi3nt.spline.curve.controller.CurveController;
+
+public interface CardinalCurveController extends CurveController {
+
+ float getPositionA();
+ float getPositionB();
+ float getPositionC();
+ float getPositionD();
+
+ float getScale();
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java
new file mode 100644
index 0000000..8d491bd
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/curve/curves/cardinal/CatmullRomCurve.java
@@ -0,0 +1,27 @@
+package fr.radi3nt.spline.curve.curves.cardinal;
+
+import fr.radi3nt.spline.curve.CharacteristicCurve;
+
+public class CatmullRomCurve extends CharacteristicCurve {
+
+ private final float pointA;
+ private final float pointB;
+ private final float pointC;
+ private final float pointD;
+
+ public CatmullRomCurve(float pointA, float pointB, float pointC, float pointD) {
+ this.pointA = pointA;
+ this.pointB = pointB;
+ this.pointC = pointC;
+ this.pointD = pointD;
+ }
+
+ @Override
+ protected float computeP(float a, float t, float t2, float t3) {
+ float p = a * 2 * pointB
+ + t *(-pointA+pointC)
+ + t2 *(2*pointA-5*pointB+4*pointC-pointD)
+ + t3 *(-pointA+3*pointB-3*pointC+pointD);
+ return p/2;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java
new file mode 100644
index 0000000..9b42944
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/SplineReader.java
@@ -0,0 +1,69 @@
+package fr.radi3nt.spline.imports;
+
+import fr.radi3nt.spline.imports.key.CurveHandleData;
+import fr.radi3nt.spline.imports.key.InterpolationType;
+import fr.radi3nt.spline.imports.key.KeyData;
+import fr.radi3nt.spline.imports.spline.KeyedSplineBuilder;
+import fr.radi3nt.spline.splines.dimensions.Spline2D;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SplineReader {
+
+ private final KeyedSplineBuilder splineBuilder;
+
+ public SplineReader(KeyedSplineBuilder splineBuilder) {
+ this.splineBuilder = splineBuilder;
+ }
+
+ public Spline2D build(BufferedReader content, float scaleX) throws IOException {
+ return splineBuilder.build(getKeyData(content), scaleX);
+ }
+
+ private List getKeyData(BufferedReader content) throws IOException {
+ List keyData = new ArrayList<>();
+ String line;
+ while ((line = content.readLine())!=null) {
+ line = formatLine(line);
+ if (line.isEmpty())
+ continue;
+ if (line.startsWith("}"))
+ break;
+ String[] splitLine = line.split(" ");
+ float frameIndex = Float.parseFloat(splitLine[0]);
+ float correspondingValue = Float.parseFloat(splitLine[1]);
+ InterpolationType inInterpolation = InterpolationType.valueOf(splitLine[2].toUpperCase());
+ InterpolationType outInterpolation = InterpolationType.valueOf(splitLine[3].toUpperCase());
+ boolean tanLocked = stringToBool(splitLine[4]);
+ boolean weightLocked = stringToBool(splitLine[5]);
+
+ int additionalDataAmount = splitLine.length-7;
+ int curveHandleDataAmount = Math.floorDiv(additionalDataAmount, 2);
+ CurveHandleData[] curveHandleData = new CurveHandleData[curveHandleDataAmount];
+ for (int i = 0; i < curveHandleDataAmount; i++) {
+ String tanAngle = splitLine[7+i*2];
+ String tanWeight = splitLine[8+i*2];
+ curveHandleData[i] = new CurveHandleData(Float.parseFloat(tanAngle), Float.parseFloat(tanWeight));
+ }
+
+ keyData.add(new KeyData(frameIndex, correspondingValue, inInterpolation, outInterpolation, tanLocked, weightLocked, curveHandleData));
+ }
+ return keyData;
+ }
+
+ private String formatLine(String s) {
+ String formatted = s.trim();
+ int index = formatted.lastIndexOf(";");
+ if (index!=-1)
+ formatted = formatted.substring(0, index);
+ return formatted;
+ }
+
+ private boolean stringToBool(String str) {
+ return str.equals("1");
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/CurveHandleData.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/CurveHandleData.java
new file mode 100644
index 0000000..ab5d73c
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/CurveHandleData.java
@@ -0,0 +1,28 @@
+package fr.radi3nt.spline.imports.key;
+
+public class CurveHandleData {
+
+ private final float tangentAngle;
+ private final float tangentWeight;
+
+ public CurveHandleData(float tangentAngle, float tangentWeight) {
+ this.tangentAngle = tangentAngle;
+ this.tangentWeight = tangentWeight;
+ }
+
+ public float getTangentAngle() {
+ return tangentAngle;
+ }
+
+ public float getTangentWeight() {
+ return tangentWeight;
+ }
+
+ @Override
+ public String toString() {
+ return "CurveHandleData{" +
+ "tangentAngle=" + tangentAngle +
+ ", tangentWeight=" + tangentWeight +
+ '}';
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/InterpolationType.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/InterpolationType.java
new file mode 100644
index 0000000..664199b
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/InterpolationType.java
@@ -0,0 +1,12 @@
+package fr.radi3nt.spline.imports.key;
+
+public enum InterpolationType {
+
+ LINEAR,
+ AUTO,
+ SPLINE,
+ FIXED,
+ STEP,
+ FLAT,
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyData.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyData.java
new file mode 100644
index 0000000..8fb80f6
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyData.java
@@ -0,0 +1,69 @@
+package fr.radi3nt.spline.imports.key;
+
+import java.util.Arrays;
+
+public class KeyData {
+
+ private final float x;
+ private final float y;
+
+ private final InterpolationType inInterpolation;
+ private final InterpolationType outInterpolation;
+
+ private final boolean tangentLocked;
+ private final boolean weightLocked;
+
+ private final CurveHandleData[] curveHandleData;
+
+
+ public KeyData(float x, float y, InterpolationType inInterpolation, InterpolationType outInterpolation, boolean tangentLocked, boolean weightLocked, CurveHandleData[] curveHandleData) {
+ this.x = x;
+ this.y = y;
+ this.inInterpolation = inInterpolation;
+ this.outInterpolation = outInterpolation;
+ this.tangentLocked = tangentLocked;
+ this.weightLocked = weightLocked;
+ this.curveHandleData = curveHandleData;
+ }
+
+ public float getX() {
+ return x;
+ }
+
+ public float getY() {
+ return y;
+ }
+
+ public InterpolationType getInInterpolation() {
+ return inInterpolation;
+ }
+
+ public InterpolationType getOutInterpolation() {
+ return outInterpolation;
+ }
+
+ public boolean isTangentLocked() {
+ return tangentLocked;
+ }
+
+ public boolean isWeightLocked() {
+ return weightLocked;
+ }
+
+ public CurveHandleData[] getCurveHandleData() {
+ return curveHandleData;
+ }
+
+ @Override
+ public String toString() {
+ return "KeyData{" +
+ "x=" + x +
+ ", y=" + y +
+ ", inInterpolation=" + inInterpolation +
+ ", outInterpolation=" + outInterpolation +
+ ", tangentLocked=" + tangentLocked +
+ ", weightLocked=" + weightLocked +
+ ", curveHandleData=" + Arrays.toString(curveHandleData) +
+ '}';
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyframesData.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyframesData.java
new file mode 100644
index 0000000..edab524
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/key/KeyframesData.java
@@ -0,0 +1,32 @@
+package fr.radi3nt.spline.imports.key;
+
+import fr.radi3nt.spline.splines.dimensions.Spline2D;
+
+import java.util.List;
+
+public class KeyframesData {
+
+ private final List keyData;
+ private final Spline2D dataSpline;
+
+ public KeyframesData(List keyData, Spline2D dataSpline) {
+ this.keyData = keyData;
+ this.dataSpline = dataSpline;
+ }
+
+ public List getKeyData() {
+ return keyData;
+ }
+
+ public Spline2D getDataSpline() {
+ return dataSpline;
+ }
+
+ @Override
+ public String toString() {
+ return "KeyframesData{" +
+ "keyData=" + keyData +
+ ", dataSpline=" + dataSpline +
+ '}';
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/BezierKeyedSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/BezierKeyedSplineBuilder.java
new file mode 100644
index 0000000..fca7823
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/BezierKeyedSplineBuilder.java
@@ -0,0 +1,111 @@
+package fr.radi3nt.spline.imports.spline;
+
+import fr.radi3nt.spline.imports.key.CurveHandleData;
+import fr.radi3nt.spline.imports.key.InterpolationType;
+import fr.radi3nt.spline.imports.key.KeyData;
+import fr.radi3nt.spline.imports.spline.handle.AutoHandleDataBuilder;
+import fr.radi3nt.spline.imports.spline.handle.FixedHandleDataBuilder;
+import fr.radi3nt.spline.imports.spline.handle.GeneratedHandleDataBuilder;
+import fr.radi3nt.spline.curve.Curve;
+import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve;
+import fr.radi3nt.spline.splines.CollectionSpline;
+import fr.radi3nt.spline.splines.Spline;
+import fr.radi3nt.spline.splines.builder.bezier.dim1.DirectCubicBezierCurveController;
+import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline2D;
+import fr.radi3nt.spline.splines.dimensions.Spline2D;
+
+import java.util.*;
+
+public class BezierKeyedSplineBuilder implements KeyedSplineBuilder {
+
+
+ private static final Map DEFAULT_MAP = new HashMap<>();
+ static {
+ DEFAULT_MAP.put(InterpolationType.FIXED, new FixedHandleDataBuilder());
+ DEFAULT_MAP.put(InterpolationType.AUTO, new AutoHandleDataBuilder());
+ DEFAULT_MAP.put(InterpolationType.SPLINE, new GeneratedHandleDataBuilder());
+ }
+
+ public static final Map DEFAULT_INTERPOLATIONS = Collections.unmodifiableMap(DEFAULT_MAP);
+
+
+ private final Map curveHandleDataBuilderMap;
+ private final float offsetX;
+ private final float offsetY;
+ private final float scaleX;
+ private final float scaleY;
+
+ public BezierKeyedSplineBuilder(Map curveHandleDataBuilderMap, float offsetX, float offsetY, float scaleX, float scaleY) {
+ this.curveHandleDataBuilderMap = curveHandleDataBuilderMap;
+ this.offsetX = offsetX;
+ this.offsetY = offsetY;
+ this.scaleX = scaleX;
+ this.scaleY = scaleY;
+ }
+
+ public static KeyedSplineBuilder newDefault(float scaleX, float scaleY) {
+ return new BezierKeyedSplineBuilder(DEFAULT_INTERPOLATIONS, 0, 0, scaleX, scaleY);
+ }
+
+ public static KeyedSplineBuilder newDefault(float offsetX, float offsetY, float scaleX, float scaleY) {
+ return new BezierKeyedSplineBuilder(DEFAULT_INTERPOLATIONS, offsetX, offsetY, scaleX, scaleY);
+ }
+
+ @Override
+ public Spline2D build(List keyData, float scaleX) {
+ List xCurves = new ArrayList<>();
+ List yCurves = new ArrayList<>();
+ Spline xSpline = new CollectionSpline(xCurves);
+ Spline ySpline = new CollectionSpline(yCurves);
+ for (int i = 0; i < keyData.size()-1; i++) {
+ KeyData start = keyData.get(i);
+ KeyData end = keyData.get(i+1);
+
+ InterpolationType startSplineType = start.getOutInterpolation();
+ InterpolationType endSplineType = end.getInInterpolation();
+
+ CurveHandleData startCurveData = curveHandleDataBuilderMap.get(startSplineType).buildStartHandleData(keyData, i, start, end);
+ CurveHandleData endCurveData = curveHandleDataBuilderMap.get(endSplineType).buildEndHandleData(keyData, i, start, end);
+
+ float cappedStartLength = capTangentLength(end.getX()-start.getX(), startCurveData);
+ float cappedEndLength = capTangentLength(end.getX()-start.getX(), endCurveData);
+
+ float startXPointControl =(start.getX()+calcPosX(startCurveData, cappedStartLength));
+ float endXPointControl = (end.getX()-calcPosX(endCurveData, cappedEndLength));
+
+ float startYPointControl = (start.getY()+calcPosY(startCurveData, cappedStartLength));
+ float endYPointControl = (end.getY()-calcPosY(endCurveData, cappedEndLength));
+
+ CubicBezierCurve curveX = new CubicBezierCurve(new DirectCubicBezierCurveController(
+ start.getX()* this.scaleX *scaleX+offsetX,
+ end.getX()* this.scaleX *scaleX+offsetX,
+ startXPointControl* this.scaleX *scaleX+offsetX,
+ endXPointControl* this.scaleX *scaleX+offsetX));
+ CubicBezierCurve curveY = new CubicBezierCurve(new DirectCubicBezierCurveController(
+ start.getY()*scaleY+offsetY,
+ end.getY()*scaleY+offsetY,
+ startYPointControl*scaleY+offsetY,
+ endYPointControl*scaleY+offsetY));
+
+ xCurves.add(curveX);
+ yCurves.add(curveY);
+ }
+
+ return new EncapsulatingSpline2D(xSpline, ySpline);
+ }
+
+
+ private float capTangentLength(float frameDelta, CurveHandleData curveHandleData) {
+ float angleProjected = (float) Math.cos(Math.toRadians(curveHandleData.getTangentAngle()));
+ float maxLength = frameDelta/angleProjected;
+ return Math.min(curveHandleData.getTangentWeight(), maxLength);
+ }
+
+ private float calcPosX(CurveHandleData curveHandleData, float length) {
+ return (float) (Math.cos(Math.toRadians(curveHandleData.getTangentAngle()))*length);
+ }
+
+ private float calcPosY(CurveHandleData curveHandleData, float length) {
+ return (float) (Math.sin(Math.toRadians(curveHandleData.getTangentAngle()))*length);
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/CurveHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/CurveHandleDataBuilder.java
new file mode 100644
index 0000000..ba1a332
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/CurveHandleDataBuilder.java
@@ -0,0 +1,13 @@
+package fr.radi3nt.spline.imports.spline;
+
+import fr.radi3nt.spline.imports.key.CurveHandleData;
+import fr.radi3nt.spline.imports.key.KeyData;
+
+import java.util.List;
+
+public interface CurveHandleDataBuilder {
+
+ CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end);
+ CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end);
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java
new file mode 100644
index 0000000..a967baa
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/KeyedSplineBuilder.java
@@ -0,0 +1,12 @@
+package fr.radi3nt.spline.imports.spline;
+
+import fr.radi3nt.spline.imports.key.KeyData;
+import fr.radi3nt.spline.splines.dimensions.Spline2D;
+
+import java.util.List;
+
+public interface KeyedSplineBuilder {
+
+ Spline2D build(List keys, float intervalDuration);
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/AutoHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/AutoHandleDataBuilder.java
new file mode 100644
index 0000000..10ef47d
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/AutoHandleDataBuilder.java
@@ -0,0 +1,11 @@
+package fr.radi3nt.spline.imports.spline.handle;
+
+import fr.radi3nt.maths.components.vectors.Vector2f;
+
+public class AutoHandleDataBuilder extends GeneratedHandleDataBuilder {
+
+ @Override
+ protected float getHandleAngle(Vector2f direction, float dirLength) {
+ return 0f;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/FixedHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/FixedHandleDataBuilder.java
new file mode 100644
index 0000000..c568eec
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/FixedHandleDataBuilder.java
@@ -0,0 +1,19 @@
+package fr.radi3nt.spline.imports.spline.handle;
+
+import fr.radi3nt.spline.imports.key.CurveHandleData;
+import fr.radi3nt.spline.imports.key.KeyData;
+import fr.radi3nt.spline.imports.spline.CurveHandleDataBuilder;
+
+import java.util.List;
+
+public class FixedHandleDataBuilder implements CurveHandleDataBuilder {
+ @Override
+ public CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end) {
+ return start.getCurveHandleData()[start.getCurveHandleData().length-1];
+ }
+
+ @Override
+ public CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end) {
+ return end.getCurveHandleData()[0];
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/GeneratedHandleDataBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/GeneratedHandleDataBuilder.java
new file mode 100644
index 0000000..96d251e
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/imports/spline/handle/GeneratedHandleDataBuilder.java
@@ -0,0 +1,63 @@
+package fr.radi3nt.spline.imports.spline.handle;
+
+import fr.radi3nt.spline.imports.key.CurveHandleData;
+import fr.radi3nt.spline.imports.key.KeyData;
+import fr.radi3nt.spline.imports.spline.CurveHandleDataBuilder;
+import fr.radi3nt.maths.components.vectors.Vector2f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector2f;
+
+import java.util.List;
+
+public class GeneratedHandleDataBuilder implements CurveHandleDataBuilder {
+ @Override
+ public CurveHandleData buildStartHandleData(List keyData, int i, KeyData start, KeyData end) {
+ Vector2f endPos = new SimpleVector2f(end.getX(), end.getY());
+ Vector2f beforeOnePos = new SimpleVector2f(start.getX(), end.getY());
+
+ float closeness = 0.5f;
+ float lengthMultiplier = 2;
+ if (i!=0) {
+ lengthMultiplier = 1f;
+ KeyData startBefore = keyData.get(i-1);
+ beforeOnePos = new SimpleVector2f(startBefore.getX(), startBefore.getY());
+ closeness = (start.getX()-beforeOnePos.getX())/(endPos.getX()-beforeOnePos.getX());
+ }
+
+ Vector2f direction = endPos.clone().sub(beforeOnePos.clone());
+ float dirLength = direction.length();
+ float angle = getHandleAngle(direction, dirLength);
+
+ return new CurveHandleData(angle, getTangentWeight(1 - closeness, dirLength, lengthMultiplier));
+ }
+
+ @Override
+ public CurveHandleData buildEndHandleData(List keyData, int i, KeyData start, KeyData end) {
+ Vector2f startPos = new SimpleVector2f(start.getX(), start.getY());
+ Vector2f afterEndPos = new SimpleVector2f(end.getX(), end.getY());
+
+ float closeness = 0.5f;
+ float lengthMultiplier = 2;
+
+ if (i=splineSegments)
+ currentGuess = splineSegments;
+ if (currentGuess<0)
+ currentGuess = 0;
+ float value = spline.interpolateX(currentGuess);
+ if (closeEnough(value, expectedX)) {
+ break;
+ }
+ float vel = spline.velocityX(currentGuess);
+ if (Math.abs(vel)<=EPSILON)
+ vel = EPSILON*Math.copySign(1, vel); //preventing catastrophic failure
+ currentGuess = currentGuess - (value-expectedX)/(vel);
+ }
+
+ if (currentGuess>=splineSegments)
+ currentGuess = splineSegments;
+ if (currentGuess<0)
+ currentGuess = 0;
+
+ return currentGuess;
+ }
+
+ private static boolean closeEnough(float currentGuess, float expectedX) {
+ return abs(currentGuess-expectedX)=plotted.length)
+ return plotted[plotted.length-1];
+
+ if (indexPlusOne>=plotted.length)
+ return plotted[index];
+
+ float startValue = plotted[index];
+ float endValue = plotted[indexPlusOne];
+ float relativeTime = t/plotInterval - index;
+
+ return relativeTime*endValue+(1-relativeTime)*startValue;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java
new file mode 100644
index 0000000..951453f
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/CollectionSpline.java
@@ -0,0 +1,67 @@
+package fr.radi3nt.spline.splines;
+
+import fr.radi3nt.spline.curve.Curve;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class CollectionSpline implements Spline {
+
+ protected final List extends Curve> curves;
+
+ public CollectionSpline(List extends Curve> curves) {
+ this.curves = curves;
+ }
+
+ @Override
+ public float interpolate(float t) {
+ int index = (int) Math.floor(t);
+ if (t==curves.size()) {
+ index = curves.size()-1;
+ if (curves.isEmpty())
+ index = 0;
+ }
+ Curve curve = getCurveAtIndex(index);
+ return curve.interpolate(t-index);
+ }
+
+ @Override
+ public float velocity(float t) {
+ int index = (int) Math.floor(t);
+ if (t==curves.size()) {
+ index = curves.size()-1;
+ if (curves.isEmpty())
+ index = 0;
+ }
+
+ Curve curve = getCurveAtIndex(index);
+ return curve.velocity(t-index);
+ }
+
+ @Override
+ public int getSegmentCount() {
+ return curves.size();
+ }
+
+ protected Curve getCurveAtIndex(int index) {
+ checkForValidIndex(index);
+ return curves.get(index);
+ }
+
+ private void checkForValidIndex(int index) {
+ if (index<0 || index>= curves.size())
+ throw new IllegalArgumentException("Index is not in bounds 0 < " + curves.size() + " (index being: " + index + ")");
+ }
+
+ public List extends Curve> getCurves() {
+ return Collections.unmodifiableList(curves);
+ }
+
+ @Override
+ public String toString() {
+ return "CollectionSpline{" +
+ "curves=" + Arrays.toString(curves.toArray(new Curve[0])) +
+ '}';
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java
new file mode 100644
index 0000000..4686aa0
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/Spline.java
@@ -0,0 +1,9 @@
+package fr.radi3nt.spline.splines;
+
+public interface Spline {
+
+ float interpolate(float t);
+ float velocity(float t);
+
+ int getSegmentCount();
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java
new file mode 100644
index 0000000..5108733
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/PositionnedSplineController.java
@@ -0,0 +1,7 @@
+package fr.radi3nt.spline.splines.builder;
+
+public interface PositionnedSplineController extends SplineController {
+
+ void setPosition(int index, float pos);
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java
new file mode 100644
index 0000000..f2d1482
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineBuilder.java
@@ -0,0 +1,9 @@
+package fr.radi3nt.spline.splines.builder;
+
+import fr.radi3nt.spline.splines.Spline;
+
+public interface SplineBuilder {
+
+ Spline build();
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java
new file mode 100644
index 0000000..75b89ed
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/SplineController.java
@@ -0,0 +1,4 @@
+package fr.radi3nt.spline.splines.builder;
+
+public interface SplineController {
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java
new file mode 100644
index 0000000..4107b3a
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/BezierPoint.java
@@ -0,0 +1,26 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim1;
+
+public class BezierPoint {
+
+ private final float point;
+ private final float pointControlBefore;
+ private final float pointControlAfter;
+
+ public BezierPoint(float point, float pointControlBefore, float pointControlAfter) {
+ this.point = point;
+ this.pointControlBefore = pointControlBefore;
+ this.pointControlAfter = pointControlAfter;
+ }
+
+ public float getPoint() {
+ return point;
+ }
+
+ public float getPointControlBefore() {
+ return pointControlBefore;
+ }
+
+ public float getPointControlAfter() {
+ return pointControlAfter;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java
new file mode 100644
index 0000000..8299d48
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineBuilder.java
@@ -0,0 +1,34 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim1;
+
+import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurve;
+import fr.radi3nt.spline.splines.CollectionSpline;
+import fr.radi3nt.spline.splines.Spline;
+import fr.radi3nt.spline.splines.builder.SplineBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CubicBezierSplineBuilder implements SplineBuilder {
+
+ private final CollectionSpline spline;
+ private final CubicBezierSplineController controller;
+
+ public CubicBezierSplineBuilder(BezierPoint[] pos) {
+ controller = new CubicBezierSplineController(pos);
+ List curves = new ArrayList<>();
+ for (int i = 0; i < pos.length-1; i++) {
+ CubicBezierCurve cardinal = new CubicBezierCurve(controller.createForIndex(i));
+ curves.add(cardinal);
+ }
+ spline = new CollectionSpline(curves);
+ }
+
+ @Override
+ public Spline build() {
+ return spline;
+ }
+
+ public CubicBezierSplineController controller() {
+ return controller;
+ }
+}
\ No newline at end of file
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java
new file mode 100644
index 0000000..d6e1ccb
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/CubicBezierSplineController.java
@@ -0,0 +1,22 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim1;
+
+import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController;
+import fr.radi3nt.spline.splines.builder.SplineController;
+
+public class CubicBezierSplineController implements SplineController {
+
+ private final BezierPoint[] positions;
+
+ public CubicBezierSplineController(BezierPoint[] positions) {
+ this.positions = positions;
+ }
+
+ public void setPoint(BezierPoint point, int index) {
+ positions[index] = point;
+ }
+
+ public CubicBezierCurveController createForIndex(int index) {
+ return new InferredCubicBezierCurveController(index, positions);
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java
new file mode 100644
index 0000000..a559d3b
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/DirectCubicBezierCurveController.java
@@ -0,0 +1,39 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim1;
+
+import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController;
+
+public class DirectCubicBezierCurveController implements CubicBezierCurveController {
+
+ private final float startPoint;
+ private final float endPoint;
+
+ private final float startPointControl;
+ private final float endPointControl;
+
+ public DirectCubicBezierCurveController(float startPoint, float endPoint, float startPointControl, float endPointControl) {
+ this.startPoint = startPoint;
+ this.endPoint = endPoint;
+ this.startPointControl = startPointControl;
+ this.endPointControl = endPointControl;
+ }
+
+ @Override
+ public float getStartPoint() {
+ return startPoint;
+ }
+
+ @Override
+ public float getEndPoint() {
+ return endPoint;
+ }
+
+ @Override
+ public float getStartPointControl() {
+ return startPointControl;
+ }
+
+ @Override
+ public float getEndPointControl() {
+ return endPointControl;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java
new file mode 100644
index 0000000..4e7bfc0
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim1/InferredCubicBezierCurveController.java
@@ -0,0 +1,35 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim1;
+
+import fr.radi3nt.spline.curve.curves.bezier.CubicBezierCurveController;
+
+public class InferredCubicBezierCurveController implements CubicBezierCurveController {
+
+ private final int index;
+
+ private final BezierPoint[] pos;
+
+ public InferredCubicBezierCurveController(int index, BezierPoint[] pos) {
+ this.index = index;
+ this.pos = pos;
+ }
+
+ @Override
+ public float getStartPoint() {
+ return pos[index].getPoint();
+ }
+
+ @Override
+ public float getStartPointControl() {
+ return pos[index].getPointControlAfter();
+ }
+
+ @Override
+ public float getEndPoint() {
+ return pos[index+1].getPoint();
+ }
+
+ @Override
+ public float getEndPointControl() {
+ return pos[index+1].getPointControlBefore();
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java
new file mode 100644
index 0000000..0648a24
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/BezierPoint2D.java
@@ -0,0 +1,26 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim2;
+
+import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint;
+
+public class BezierPoint2D {
+
+ private final BezierPoint xAxis;
+ private final BezierPoint yAxis;
+
+ public BezierPoint2D(BezierPoint xAxis, BezierPoint yAxis) {
+ this.xAxis = xAxis;
+ this.yAxis = yAxis;
+ }
+
+ public BezierPoint2D(float pointX, float pointControlBeforeX, float pointControlAfterX, float pointY, float pointControlBeforeY, float pointControlAfterY) {
+ this(new BezierPoint(pointX, pointControlBeforeX, pointControlAfterX), new BezierPoint(pointY, pointControlBeforeY, pointControlAfterY));
+ }
+
+ public BezierPoint getXAxis() {
+ return xAxis;
+ }
+
+ public BezierPoint getYAxis() {
+ return yAxis;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java
new file mode 100644
index 0000000..d59f349
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineBuilder2D.java
@@ -0,0 +1,34 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim2;
+
+import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint;
+import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineBuilder;
+import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline2D;
+import fr.radi3nt.spline.splines.dimensions.Spline2D;
+
+public class CubicBezierSplineBuilder2D {
+
+ private final CubicBezierSplineBuilder[] splineBuilders = new CubicBezierSplineBuilder[3];
+
+ public CubicBezierSplineBuilder2D(BezierPoint2D... positions) {
+ BezierPoint[] xPos = new BezierPoint[positions.length];
+ BezierPoint[] yPos = new BezierPoint[positions.length];
+
+ for (int i = 0; i < positions.length; i++) {
+ BezierPoint2D position = positions[i];
+ xPos[i] = position.getXAxis();
+ yPos[i] = position.getYAxis();
+ }
+
+ splineBuilders[0] = new CubicBezierSplineBuilder(xPos);
+ splineBuilders[1] = new CubicBezierSplineBuilder(yPos);
+ }
+
+ public Spline2D build() {
+ return new EncapsulatingSpline2D(splineBuilders[0].build(), splineBuilders[1].build());
+ }
+
+ public CubicBezierSplineController2D controller() {
+ return new CubicBezierSplineController2D(splineBuilders[0].controller(), splineBuilders[1].controller());
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java
new file mode 100644
index 0000000..727f74f
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim2/CubicBezierSplineController2D.java
@@ -0,0 +1,18 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim2;
+
+import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineController;
+
+public class CubicBezierSplineController2D {
+
+ private final CubicBezierSplineController[] controllers;
+
+ public CubicBezierSplineController2D(CubicBezierSplineController... controllers) {
+ this.controllers = controllers;
+ }
+
+
+ public void setPosition(BezierPoint2D point, int index) {
+ controllers[0].setPoint(point.getXAxis(), index);
+ controllers[1].setPoint(point.getYAxis(), index);
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java
new file mode 100644
index 0000000..6690a0e
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/BezierPoint3D.java
@@ -0,0 +1,37 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim3;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint;
+
+public class BezierPoint3D {
+
+ private final BezierPoint xAxis;
+ private final BezierPoint yAxis;
+ private final BezierPoint zAxis;
+
+ public BezierPoint3D(BezierPoint xAxis, BezierPoint yAxis, BezierPoint zAxis) {
+ this.xAxis = xAxis;
+ this.yAxis = yAxis;
+ this.zAxis = zAxis;
+ }
+
+ public BezierPoint3D(float pointX, float pointControlBeforeX, float pointControlAfterX, float pointY, float pointControlBeforeY, float pointControlAfterY, float pointZ, float pointControlBeforeZ, float pointControlAfterZ) {
+ this(new BezierPoint(pointX, pointControlBeforeX, pointControlAfterX), new BezierPoint(pointY, pointControlBeforeY, pointControlAfterY), new BezierPoint(pointZ, pointControlBeforeZ, pointControlAfterZ));
+ }
+
+ public BezierPoint3D(Vector3f position, Vector3f beforeDirection, Vector3f afterDirection) {
+ this(new BezierPoint(position.getX(), beforeDirection.getX(), afterDirection.getX()), new BezierPoint(position.getY(), beforeDirection.getY(), afterDirection.getY()), new BezierPoint(position.getZ(), beforeDirection.getZ(), afterDirection.getZ()));
+ }
+
+ public BezierPoint getXAxis() {
+ return xAxis;
+ }
+
+ public BezierPoint getYAxis() {
+ return yAxis;
+ }
+
+ public BezierPoint getZAxis() {
+ return zAxis;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java
new file mode 100644
index 0000000..71bca23
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineBuilder3D.java
@@ -0,0 +1,62 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim3;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.spline.splines.builder.bezier.dim1.BezierPoint;
+import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineBuilder;
+import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D;
+import fr.radi3nt.spline.splines.dimensions.Spline3D;
+
+public class CubicBezierSplineBuilder3D {
+
+ private final CubicBezierSplineBuilder[] splineBuilders = new CubicBezierSplineBuilder[3];
+
+ public static CubicBezierSplineBuilder3D fromTwoPoints(Vector3f pointA, Vector3f dirA, Vector3f pointB, Vector3f dirB) {
+ return new CubicBezierSplineBuilder3D(
+ new BezierPoint3D(pointA.getX(), 0, pointA.getX()+dirA.getX(), pointA.getY(), 0, pointA.getY()+dirA.getY(), pointA.getZ(), 0, pointA.getZ()+dirA.getZ()),
+ new BezierPoint3D(pointB.getX(), pointB.getX()+dirB.getX(), 0, pointB.getY(), pointB.getY()+dirB.getY(), 0, pointB.getZ(), pointB.getZ()+dirB.getZ(), 0)
+ );
+ }
+
+ public CubicBezierSplineBuilder3D(BezierPoint3D... positions) {
+ BezierPoint[] xPos = new BezierPoint[positions.length];
+ BezierPoint[] yPos = new BezierPoint[positions.length];
+ BezierPoint[] zPos = new BezierPoint[positions.length];
+
+ for (int i = 0; i < positions.length; i++) {
+ BezierPoint3D position = positions[i];
+ xPos[i] = position.getXAxis();
+ yPos[i] = position.getYAxis();
+ zPos[i] = position.getZAxis();
+ }
+
+ splineBuilders[0] = new CubicBezierSplineBuilder(xPos);
+ splineBuilders[1] = new CubicBezierSplineBuilder(yPos);
+ splineBuilders[2] = new CubicBezierSplineBuilder(zPos);
+ }
+
+ public CubicBezierSplineBuilder3D(int length) {
+ BezierPoint[] xPos = new BezierPoint[length];
+ BezierPoint[] yPos = new BezierPoint[length];
+ BezierPoint[] zPos = new BezierPoint[length];
+
+ for (int i = 0; i < length; i++) {
+ BezierPoint3D position = new BezierPoint3D(0, 0, 0, 0, 0, 0, 0, 0, 0);
+ xPos[i] = position.getXAxis();
+ yPos[i] = position.getYAxis();
+ zPos[i] = position.getZAxis();
+ }
+
+ splineBuilders[0] = new CubicBezierSplineBuilder(xPos);
+ splineBuilders[1] = new CubicBezierSplineBuilder(yPos);
+ splineBuilders[2] = new CubicBezierSplineBuilder(zPos);
+ }
+
+ public Spline3D build() {
+ return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build());
+ }
+
+ public CubicBezierSplineController3D controller() {
+ return new CubicBezierSplineController3D(splineBuilders[0].controller(), splineBuilders[1].controller(), splineBuilders[2].controller());
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java
new file mode 100644
index 0000000..cb72a86
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bezier/dim3/CubicBezierSplineController3D.java
@@ -0,0 +1,19 @@
+package fr.radi3nt.spline.splines.builder.bezier.dim3;
+
+import fr.radi3nt.spline.splines.builder.bezier.dim1.CubicBezierSplineController;
+
+public class CubicBezierSplineController3D {
+
+ private final CubicBezierSplineController[] controllers;
+
+ public CubicBezierSplineController3D(CubicBezierSplineController... controllers) {
+ this.controllers = controllers;
+ }
+
+
+ public void setPosition(BezierPoint3D point, int index) {
+ controllers[0].setPoint(point.getXAxis(), index);
+ controllers[1].setPoint(point.getYAxis(), index);
+ controllers[2].setPoint(point.getZAxis(), index);
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java
new file mode 100644
index 0000000..2acc9d6
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineBuilder.java
@@ -0,0 +1,34 @@
+package fr.radi3nt.spline.splines.builder.bspline.dim1;
+
+import fr.radi3nt.spline.curve.curves.bcurve.BCurve;
+import fr.radi3nt.spline.splines.CollectionSpline;
+import fr.radi3nt.spline.splines.Spline;
+import fr.radi3nt.spline.splines.builder.SplineBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BSplineBuilder implements SplineBuilder {
+
+ private final CollectionSpline spline;
+ private final BSplineController controller;
+
+ public BSplineBuilder(float[] pos) {
+ controller = new BSplineController(pos);
+ List curves = new ArrayList<>();
+ for (int i = 0; i < pos.length-1; i++) {
+ BCurve cardinal = new BCurve(controller.createForIndex(i));
+ curves.add(cardinal);
+ }
+ spline = new CollectionSpline(curves);
+ }
+
+ @Override
+ public Spline build() {
+ return spline;
+ }
+
+ public BSplineController controller() {
+ return controller;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java
new file mode 100644
index 0000000..52e29eb
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/BSplineController.java
@@ -0,0 +1,23 @@
+package fr.radi3nt.spline.splines.builder.bspline.dim1;
+
+import fr.radi3nt.spline.curve.curves.bcurve.BCurveController;
+import fr.radi3nt.spline.splines.builder.PositionnedSplineController;
+
+public class BSplineController implements PositionnedSplineController {
+
+ private final float[] positions;
+
+ public BSplineController(float[] positions) {
+ this.positions = positions;
+ }
+
+ @Override
+ public void setPosition(int index, float pos) {
+ positions[index] = pos;
+ }
+
+ public BCurveController createForIndex(int index) {
+ return new InferredBCurveController(index, positions);
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java
new file mode 100644
index 0000000..0e1ef0e
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/DirectBCurveController.java
@@ -0,0 +1,38 @@
+package fr.radi3nt.spline.splines.builder.bspline.dim1;
+
+import fr.radi3nt.spline.curve.curves.bcurve.BCurveController;
+
+public class DirectBCurveController implements BCurveController {
+
+ private final float positionA;
+ private final float positionB;
+ private final float positionC;
+ private final float positionD;
+
+ public DirectBCurveController(float positionA, float positionB, float positionC, float positionD) {
+ this.positionA = positionA;
+ this.positionB = positionB;
+ this.positionC = positionC;
+ this.positionD = positionD;
+ }
+
+ @Override
+ public float getPositionA() {
+ return positionA;
+ }
+
+ @Override
+ public float getPositionB() {
+ return positionB;
+ }
+
+ @Override
+ public float getPositionC() {
+ return positionC;
+ }
+
+ @Override
+ public float getPositionD() {
+ return positionD;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java
new file mode 100644
index 0000000..c8e91eb
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim1/InferredBCurveController.java
@@ -0,0 +1,38 @@
+package fr.radi3nt.spline.splines.builder.bspline.dim1;
+
+import fr.radi3nt.spline.curve.curves.bcurve.BCurveController;
+
+public class InferredBCurveController implements BCurveController {
+
+ private final int index;
+ private final float[] pos;
+
+ public InferredBCurveController(int index, float[] pos) {
+ this.index = index;
+ this.pos = pos;
+ }
+
+ @Override
+ public float getPositionA() {
+ return index == 0 ? (mirror(pos[index], pos[index + 1])) : pos[index - 1];
+ }
+
+ @Override
+ public float getPositionB() {
+ return pos[index];
+ }
+
+ @Override
+ public float getPositionC() {
+ return index + 1 >= pos.length ? mirror(getPositionB(), getPositionA()) : pos[index + 1];
+ }
+
+ @Override
+ public float getPositionD() {
+ return index == pos.length - 2 ? mirror(getPositionC(), getPositionB()) : pos[index + 2];
+ }
+
+ private float mirror(float middlePos, float endPos) {
+ return middlePos*2 - endPos;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java
new file mode 100644
index 0000000..eff2f87
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineBuilder3D.java
@@ -0,0 +1,46 @@
+package fr.radi3nt.spline.splines.builder.bspline.dim3;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.spline.splines.builder.bspline.dim1.BSplineBuilder;
+import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D;
+import fr.radi3nt.spline.splines.dimensions.Spline3D;
+
+public class BSplineBuilder3D {
+
+ private final BSplineBuilder[] splineBuilders = new BSplineBuilder[3];
+
+ public BSplineBuilder3D(Vector3f... positions) {
+ float[] xPos = new float[positions.length];
+ float[] yPos = new float[positions.length];
+ float[] zPos = new float[positions.length];
+
+ for (int i = 0; i < positions.length; i++) {
+ Vector3f position = positions[i];
+ xPos[i] = position.getX();
+ yPos[i] = position.getY();
+ zPos[i] = position.getZ();
+ }
+
+ splineBuilders[0] = new BSplineBuilder(xPos);
+ splineBuilders[1] = new BSplineBuilder(yPos);
+ splineBuilders[2] = new BSplineBuilder(zPos);
+ }
+
+ public BSplineBuilder3D(int count) {
+ float[] xPos = new float[count];
+ float[] yPos = new float[count];
+ float[] zPos = new float[count];
+
+ splineBuilders[0] = new BSplineBuilder(xPos);
+ splineBuilders[1] = new BSplineBuilder(yPos);
+ splineBuilders[2] = new BSplineBuilder(zPos);
+ }
+
+ public Spline3D build() {
+ return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build());
+ }
+
+ public BSplineController3D controller() {
+ return new BSplineController3D(splineBuilders[0].controller(), splineBuilders[1].controller(), splineBuilders[2].controller());
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java
new file mode 100644
index 0000000..adccd63
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/bspline/dim3/BSplineController3D.java
@@ -0,0 +1,19 @@
+package fr.radi3nt.spline.splines.builder.bspline.dim3;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.spline.splines.builder.bspline.dim1.BSplineController;
+
+public class BSplineController3D {
+
+ private final BSplineController[] controllers;
+
+ public BSplineController3D(BSplineController... controllers) {
+ this.controllers = controllers;
+ }
+
+ public void setPosition(int index, Vector3f position) {
+ controllers[0].setPosition(index, position.getX());
+ controllers[1].setPosition(index, position.getY());
+ controllers[2].setPosition(index, position.getZ());
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java
new file mode 100644
index 0000000..2e04061
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineBuilder.java
@@ -0,0 +1,34 @@
+package fr.radi3nt.spline.splines.builder.cardinal.dim1;
+
+import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurve;
+import fr.radi3nt.spline.splines.CollectionSpline;
+import fr.radi3nt.spline.splines.Spline;
+import fr.radi3nt.spline.splines.builder.SplineBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CardinalSplineBuilder implements SplineBuilder {
+
+ private final CollectionSpline spline;
+ private final CardinalSplineController controller;
+
+ public CardinalSplineBuilder(float[] pos, float scale) {
+ controller = new CardinalSplineController(pos, scale);
+ List curves = new ArrayList<>();
+ for (int i = 0; i < pos.length-1; i++) {
+ CardinalCurve cardinal = new CardinalCurve(controller.createForIndex(i));
+ curves.add(cardinal);
+ }
+ spline = new CollectionSpline(curves);
+ }
+
+ @Override
+ public Spline build() {
+ return spline;
+ }
+
+ public CardinalSplineController controller() {
+ return controller;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java
new file mode 100644
index 0000000..71a4d91
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/CardinalSplineController.java
@@ -0,0 +1,32 @@
+package fr.radi3nt.spline.splines.builder.cardinal.dim1;
+
+import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController;
+import fr.radi3nt.spline.splines.builder.PositionnedSplineController;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public class CardinalSplineController implements PositionnedSplineController {
+
+
+ private final float[] positions;
+ private final AtomicReference scale;
+
+ public CardinalSplineController(float[] positions, float scale) {
+ this.positions = positions;
+ this.scale = new AtomicReference<>(scale);
+ }
+
+ @Override
+ public void setPosition(int index, float pos) {
+ positions[index] = pos;
+ }
+
+ public void setScale(float scale) {
+ this.scale.set(scale);
+ }
+
+ public CardinalCurveController createForIndex(int index) {
+ return new InferredCardinalCurveController(index, positions, scale);
+ }
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java
new file mode 100644
index 0000000..9f2da12
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/DirectCardinalCurveController.java
@@ -0,0 +1,45 @@
+package fr.radi3nt.spline.splines.builder.cardinal.dim1;
+
+import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController;
+
+public class DirectCardinalCurveController implements CardinalCurveController {
+
+ private final float positionA;
+ private final float positionB;
+ private final float positionC;
+ private final float positionD;
+ private final float scale;
+
+ public DirectCardinalCurveController(float positionA, float positionB, float positionC, float positionD, float scale) {
+ this.positionA = positionA;
+ this.positionB = positionB;
+ this.positionC = positionC;
+ this.positionD = positionD;
+ this.scale = scale;
+ }
+
+ @Override
+ public float getPositionA() {
+ return positionA;
+ }
+
+ @Override
+ public float getPositionB() {
+ return positionB;
+ }
+
+ @Override
+ public float getPositionC() {
+ return positionC;
+ }
+
+ @Override
+ public float getPositionD() {
+ return positionD;
+ }
+
+ @Override
+ public float getScale() {
+ return scale;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java
new file mode 100644
index 0000000..7b0ee9f
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim1/InferredCardinalCurveController.java
@@ -0,0 +1,48 @@
+package fr.radi3nt.spline.splines.builder.cardinal.dim1;
+
+import fr.radi3nt.spline.curve.curves.cardinal.CardinalCurveController;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public class InferredCardinalCurveController implements CardinalCurveController {
+
+ private final int index;
+
+ private final float[] pos;
+ private final AtomicReference scale;
+
+ public InferredCardinalCurveController(int index, float[] pos, AtomicReference scale) {
+ this.index = index;
+ this.pos = pos;
+ this.scale = scale;
+ }
+
+ @Override
+ public float getPositionA() {
+ return index == 0 ? (mirror(pos[index], pos[index + 1])) : pos[index - 1];
+ }
+
+ @Override
+ public float getPositionB() {
+ return pos[index];
+ }
+
+ @Override
+ public float getPositionC() {
+ return index + 1 >= pos.length ? mirror(getPositionB(), getPositionA()) : pos[index + 1];
+ }
+
+ @Override
+ public float getPositionD() {
+ return index == pos.length - 2 ? mirror(getPositionC(), getPositionB()) : pos[index + 2];
+ }
+
+ @Override
+ public float getScale() {
+ return scale.get();
+ }
+
+ private float mirror(float middlePos, float endPos) {
+ return middlePos*2 - endPos;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java
new file mode 100644
index 0000000..6e718e8
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineBuilder3D.java
@@ -0,0 +1,36 @@
+package fr.radi3nt.spline.splines.builder.cardinal.dim3;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineBuilder;
+import fr.radi3nt.spline.splines.dimensions.EncapsulatingSpline3D;
+import fr.radi3nt.spline.splines.dimensions.Spline3D;
+
+public class CardinalSplineBuilder3D {
+
+ private final CardinalSplineBuilder[] splineBuilders = new CardinalSplineBuilder[3];
+
+ public CardinalSplineBuilder3D(Vector3f[] positions, float scale) {
+ float[] xPos = new float[positions.length];
+ float[] yPos = new float[positions.length];
+ float[] zPos = new float[positions.length];
+
+ for (int i = 0; i < positions.length; i++) {
+ Vector3f position = positions[i];
+ xPos[i] = position.getX();
+ yPos[i] = position.getY();
+ zPos[i] = position.getZ();
+ }
+
+ splineBuilders[0] = new CardinalSplineBuilder(xPos, scale);
+ splineBuilders[1] = new CardinalSplineBuilder(yPos, scale);
+ splineBuilders[2] = new CardinalSplineBuilder(zPos, scale);
+ }
+
+ public Spline3D build() {
+ return new EncapsulatingSpline3D(splineBuilders[0].build(), splineBuilders[1].build(), splineBuilders[2].build());
+ }
+
+ public CardinalSplineController3D controller() {
+ return new CardinalSplineController3D(splineBuilders[0].controller(), splineBuilders[1].controller(), splineBuilders[2].controller());
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java
new file mode 100644
index 0000000..bf6bd3b
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/builder/cardinal/dim3/CardinalSplineController3D.java
@@ -0,0 +1,26 @@
+package fr.radi3nt.spline.splines.builder.cardinal.dim3;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.spline.splines.builder.cardinal.dim1.CardinalSplineController;
+
+public class CardinalSplineController3D {
+
+ private final CardinalSplineController[] controllers;
+
+ public CardinalSplineController3D(CardinalSplineController... controllers) {
+ this.controllers = controllers;
+ }
+
+
+ public void setPosition(int index, Vector3f position) {
+ controllers[0].setPosition(index, position.getX());
+ controllers[1].setPosition(index, position.getY());
+ controllers[2].setPosition(index, position.getZ());
+ }
+
+ public void setScale(float scale) {
+ for (CardinalSplineController controller : controllers) {
+ controller.setScale(scale);
+ }
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java
new file mode 100644
index 0000000..a49e34e
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline2D.java
@@ -0,0 +1,71 @@
+package fr.radi3nt.spline.splines.dimensions;
+
+import fr.radi3nt.maths.components.vectors.Vector2f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector2f;
+import fr.radi3nt.spline.splines.Spline;
+
+import java.util.Arrays;
+
+public class EncapsulatingSpline2D implements Spline2D {
+
+ private final Spline[] splines;
+
+ public EncapsulatingSpline2D(Spline... splines) {
+ this.splines = splines;
+ }
+
+
+ @Override
+ public float interpolateX(float t) {
+ return splines[0].interpolate(t);
+ }
+
+ @Override
+ public float interpolateY(float t) {
+ return splines[1].interpolate(t);
+ }
+
+ @Override
+ public Vector2f interpolate(float t) {
+ return new SimpleVector2f(interpolateIndex(0, t), interpolateIndex(1, t));
+ }
+
+ @Override
+ public float velocityX(float t) {
+ return splines[0].velocity(t);
+ }
+
+ @Override
+ public float velocityY(float t) {
+ return splines[1].velocity(t);
+ }
+
+ private float interpolateIndex(int index, float t) {
+ return splines[index].interpolate(t);
+ }
+
+ @Override
+ public Vector2f velocity(float t) {
+ return new SimpleVector2f(velocityIndex(0, t), velocityIndex(1, t));
+ }
+
+ @Override
+ public int getSegmentCount() {
+ return splines[0].getSegmentCount();
+ }
+
+ private float velocityIndex(int index, float t) {
+ return splines[index].velocity(t);
+ }
+
+ public Spline[] getSplines() {
+ return splines;
+ }
+
+ @Override
+ public String toString() {
+ return "EncapsulatingSpline2D{" +
+ "splines=" + Arrays.toString(splines) +
+ '}';
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java
new file mode 100644
index 0000000..4010919
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/EncapsulatingSpline3D.java
@@ -0,0 +1,37 @@
+package fr.radi3nt.spline.splines.dimensions;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+import fr.radi3nt.spline.splines.Spline;
+
+public class EncapsulatingSpline3D implements Spline3D {
+
+ private final Spline[] splines;
+
+ public EncapsulatingSpline3D(Spline... splines) {
+ this.splines = splines;
+ }
+
+
+ @Override
+ public Vector3f interpolate(float t) {
+ return new SimpleVector3f(interpolateIndex(0, t), interpolateIndex(1, t), interpolateIndex(2, t));
+ }
+
+ private float interpolateIndex(int index, float t) {
+ return splines[index].interpolate(t);
+ }
+
+ @Override
+ public Vector3f velocity(float t) {
+ return new SimpleVector3f(velocityIndex(0, t), velocityIndex(1, t), velocityIndex(2, t));
+ }
+
+ private float velocityIndex(int index, float t) {
+ return splines[index].velocity(t);
+ }
+
+ public Spline[] getSplines() {
+ return splines;
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java
new file mode 100644
index 0000000..e16a0dd
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline2D.java
@@ -0,0 +1,17 @@
+package fr.radi3nt.spline.splines.dimensions;
+
+import fr.radi3nt.maths.components.vectors.Vector2f;
+
+public interface Spline2D {
+
+ float interpolateX(float t);
+ float interpolateY(float t);
+
+ Vector2f interpolate(float t);
+ float velocityX(float t);
+ float velocityY(float t);
+ Vector2f velocity(float t);
+
+ int getSegmentCount();
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java
new file mode 100644
index 0000000..0a6eebc
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/dimensions/Spline3D.java
@@ -0,0 +1,10 @@
+package fr.radi3nt.spline.splines.dimensions;
+
+import fr.radi3nt.maths.components.vectors.Vector3f;
+
+public interface Spline3D {
+
+ Vector3f interpolate(float t);
+ Vector3f velocity(float t);
+
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java
new file mode 100644
index 0000000..66938a7
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/cardinal/CardinalUsingHermitSpline.java
@@ -0,0 +1,48 @@
+package fr.radi3nt.spline.splines.hybrid.cardinal;
+
+import fr.radi3nt.spline.splines.Spline;
+import fr.radi3nt.spline.splines.hybrid.hermite.HermiteSpline;
+
+public class CardinalUsingHermitSpline implements Spline {
+
+ private final HermiteSpline hermiteSpline;
+
+ public CardinalUsingHermitSpline(float[] pos, float scale) {
+ float[] velocities = new float[pos.length];
+ for (int i = 0; i < pos.length; i++) {
+ int startIndex = i-1;
+ int endIndex = i+1;
+ float firstPos;
+ if (startIndex<0)
+ firstPos = pos[i]*2-pos[i+1];
+ else
+ firstPos = pos[i-1];
+
+ float secondPos;
+ if (endIndex>=pos.length)
+ secondPos = pos[i]*2-pos[i-1];
+ else
+ secondPos = pos[i+1];
+
+ float vel = secondPos-firstPos;
+ velocities[i] = vel*scale;
+ }
+
+ hermiteSpline = new HermiteSpline(pos, velocities);
+ }
+
+ @Override
+ public float interpolate(float t) {
+ return hermiteSpline.interpolate(t);
+ }
+
+ @Override
+ public float velocity(float t) {
+ return hermiteSpline.velocity(t);
+ }
+
+ @Override
+ public int getSegmentCount() {
+ return hermiteSpline.getSegmentCount();
+ }
+}
diff --git a/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java
new file mode 100644
index 0000000..d4d72ef
--- /dev/null
+++ b/SplineHelper/src/main/java/fr/radi3nt/spline/splines/hybrid/hermite/HermiteSpline.java
@@ -0,0 +1,32 @@
+package fr.radi3nt.spline.splines.hybrid.hermite;
+
+import fr.radi3nt.spline.curve.Curve;
+import fr.radi3nt.spline.curve.curves.HermiteCurve;
+import fr.radi3nt.spline.splines.CollectionSpline;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HermiteSpline extends CollectionSpline {
+
+ public HermiteSpline(float[] pos, float[] velocities) {
+ this(new ArrayList<>(), pos, velocities);
+ }
+
+ public HermiteSpline(List curves, float[] pos, float[] velocities) {
+ super(curves);
+ for (int i = 0; i < velocities.length-1; i++) {
+ float currentPos = pos[i];
+ float nextPos = pos[i+1];
+ float currentVel = velocities[i];
+ float nextVel = velocities[i+1];
+
+ curves.add(new HermiteCurve(currentPos, nextPos, currentVel, nextVel));
+ }
+ }
+
+ @Override
+ public float interpolate(float t) {
+ return super.interpolate(t);
+ }
+}
diff --git a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java
index c11466d..9b1e5f2 100644
--- a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java
+++ b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/ManagerTask.java
@@ -9,4 +9,5 @@ public interface ManagerTask {
long getId();
+ void waitTillFinished() throws InterruptedException;
}
diff --git a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java
index 61a4a24..c2c3ba6 100644
--- a/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java
+++ b/TimingHelper/src/main/java/fr/radi3nt/tasks/tasks/TemplateManagerTask.java
@@ -21,6 +21,16 @@ public void run() {
started = true;
run_();
finished = true;
+ synchronized (this) {
+ this.notifyAll();
+ }
+ }
+
+ @Override
+ public void waitTillFinished() throws InterruptedException {
+ synchronized (this) {
+ this.wait();
+ }
}
protected abstract void run_();
diff --git a/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java b/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java
index 45a9404..9389652 100644
--- a/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java
+++ b/TimingHelper/src/main/java/fr/radi3nt/timer/JavaSyncTimer.java
@@ -7,6 +7,14 @@ public class JavaSyncTimer implements SyncTimer {
private double fps;
private double delta;
+ public JavaSyncTimer(double delta) {
+ this.delta = delta;
+ this.fps = 1d / delta;
+ }
+
+ public JavaSyncTimer() {
+ }
+
@Override
public void start() {
lastTime = System.nanoTime();
diff --git a/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java b/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java
index 6253e8a..969bd67 100644
--- a/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java
+++ b/TimingHelper/src/main/java/fr/radi3nt/timing/Timing.java
@@ -37,9 +37,9 @@ public static Timing from(int amount, TimeConvention... time) {
}
public void waitUtilExpired() {
- while (!isExpired()) {
+ synchronized (this) {
try {
- Thread.sleep(remainingTime());
+ this.wait(remainingTime());
} catch (InterruptedException e) {
e.printStackTrace();
}
diff --git a/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java b/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java
index f9b2124..0580ca5 100644
--- a/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java
+++ b/TimingHelper/src/main/java/fr/radi3nt/timing/TimingUtil.java
@@ -4,13 +4,11 @@
public class TimingUtil {
- public static void waitUntilTaskFinished(ManagerTask GLTask) {
- while (!GLTask.isFinished()) {
- try {
- Thread.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ public static void waitUntilTaskFinished(ManagerTask gLTask) {
+ try {
+ gLTask.waitTillFinished();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
}
}
diff --git a/glTF/pom.xml b/glTF/pom.xml
new file mode 100644
index 0000000..9998786
--- /dev/null
+++ b/glTF/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ fr.radi3nt
+ JavaUtil
+ 1.0
+
+
+ glTF
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+ fr.radi3nt
+ MathsHelper
+ 1.0
+ compile
+
+
+ fr.radi3nt
+ FileHelper
+ 1.0
+ compile
+
+
+ fr.radi3nt
+ JsonHelper
+ 1.0
+ compile
+
+
+
+
\ No newline at end of file
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java
new file mode 100644
index 0000000..cb19733
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/GltfAllImporter.java
@@ -0,0 +1,45 @@
+package fr.radi3nt.gltf;
+
+import fr.radi3nt.file.impl.ResourceFile;
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.importer.*;
+import fr.radi3nt.json.Json;
+import fr.radi3nt.json.JsonValue;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class GltfAllImporter {
+
+ public GlTFResult importFile(String fullPath) throws IOException {
+ int last = fullPath.lastIndexOf("/");
+ String path = fullPath.substring(0, last);
+ String name = fullPath.substring(last+1);
+ return importFile(path, name);
+ }
+
+ public GlTFResult importFile(String parent, String fileName) throws IOException {
+ GlTFResult result = new GlTFResult();
+
+
+ Collection importers = new ArrayList<>();
+ {
+ importers.add(new AccessorsImporter());
+ importers.add(new MaterialsImporter());
+ importers.add(new MeshesImporter());
+ importers.add(new NodesImporter());
+ importers.add(new ScenesImporter());
+ importers.add(new SkinsImporter());
+ importers.add(new ViewImporter());
+ }
+ importers.add(new BuffersImporter(parent));
+
+ JsonValue parsed = Json.parse(new InputStreamReader(new ResourceFile(parent + "/" + fileName).getInputStream()));
+ importers.parallelStream().forEach(importer -> importer.parse(parsed.asObject(), result));
+
+ return result;
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java b/glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java
new file mode 100644
index 0000000..6051071
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/GlTFResult.java
@@ -0,0 +1,49 @@
+package fr.radi3nt.gltf.data;
+
+import fr.radi3nt.gltf.data.buffer.GlTFBuffer;
+import fr.radi3nt.gltf.data.buffer.accessor.BufferAccessor;
+import fr.radi3nt.gltf.data.buffer.view.BufferView;
+import fr.radi3nt.gltf.data.mesh.GlTFMesh;
+import fr.radi3nt.gltf.data.mesh.material.GlTFMaterial;
+import fr.radi3nt.gltf.data.scene.GlTFNode;
+import fr.radi3nt.gltf.data.scene.GlTFScene;
+import fr.radi3nt.gltf.data.skins.GlTFSkin;
+
+import java.util.Arrays;
+
+public class GlTFResult {
+
+ public GlTFScene[] scenes;
+ public GlTFNode[] nodes;
+
+ public GlTFMesh[] meshes;
+ public GlTFSkin[] skins;
+ public GlTFMaterial[] materials;
+
+ public BufferAccessor[] bufferAccessors;
+ public BufferView[] bufferViews;
+ public GlTFBuffer[] buffers;
+
+ @Override
+ public String toString() {
+ return "GlTFResult{" +
+ "scenes=" + Arrays.toString(scenes) +
+ ", nodes=" + Arrays.toString(nodes) +
+ ", meshes=" + Arrays.toString(meshes) +
+ ", skins=" + Arrays.toString(skins) +
+ ", materials=" + Arrays.toString(materials) +
+ ", bufferAccessors=" + Arrays.toString(bufferAccessors) +
+ ", bufferViews=" + Arrays.toString(bufferViews) +
+ ", buffers=" + Arrays.toString(buffers) +
+ '}';
+ }
+
+ public GlTFNode getNodeByName(String name) {
+ for (GlTFNode node : nodes) {
+ if (node.getName().equals(name)) {
+ return node;
+ }
+ }
+ return null;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java
new file mode 100644
index 0000000..cde325b
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/EnumGLTFAttribute.java
@@ -0,0 +1,18 @@
+package fr.radi3nt.gltf.data.attributes;
+
+public enum EnumGLTFAttribute implements GlTFAttribute {
+
+ POSITION,
+ NORMAL,
+ JOINTS_0,
+ JOINTS_1,
+ WEIGHTS_0,
+ WEIGHTS_1
+
+ ;
+
+ @Override
+ public String getId() {
+ return name();
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java
new file mode 100644
index 0000000..10699b5
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/GlTFAttribute.java
@@ -0,0 +1,7 @@
+package fr.radi3nt.gltf.data.attributes;
+
+public interface GlTFAttribute {
+
+ String getId();
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java
new file mode 100644
index 0000000..9776953
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/attributes/StringGLTFAttribute.java
@@ -0,0 +1,15 @@
+package fr.radi3nt.gltf.data.attributes;
+
+public class StringGLTFAttribute implements GlTFAttribute {
+
+ private final String id;
+
+ public StringGLTFAttribute(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java
new file mode 100644
index 0000000..0ed7d6c
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/GlTFBuffer.java
@@ -0,0 +1,77 @@
+package fr.radi3nt.gltf.data.buffer;
+
+import fr.radi3nt.file.files.ReadableFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class GlTFBuffer {
+
+ private final ReadableFile readableFile;
+ private final long byteLength;
+
+ public GlTFBuffer(ReadableFile readableFile, long byteLength) {
+ this.readableFile = readableFile;
+ this.byteLength = byteLength;
+ }
+
+ public ByteBuffer read(long offset, int length) {
+ try {
+ return tryReading(offset, length);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private ByteBuffer tryReading(long offset, int length) throws IOException {
+ InputStream inputStream = readableFile.getInputStream();
+ long totalSkipped = 0;
+ while (totalSkipped < offset) {
+ totalSkipped+=inputStream.skip(offset -totalSkipped);
+ }
+ byte[] bytes = readNBytes(inputStream, length);
+ inputStream.close();
+
+ ByteBuffer wrap = ByteBuffer.wrap(bytes);
+ wrap.order(ByteOrder.LITTLE_ENDIAN);
+ return wrap;
+ }
+
+ public void read(long offset, int length, ByteBuffer resultBuff) {
+ try {
+ tryReading(offset, length, resultBuff);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private void tryReading(long offset, int length, ByteBuffer result) throws IOException {
+ InputStream inputStream = readableFile.getInputStream();
+ long totalSkipped = 0;
+ while (totalSkipped < offset) {
+ totalSkipped+=inputStream.skip(offset -totalSkipped);
+ }
+ byte[] bytes = readNBytes(inputStream, length);
+ inputStream.close();
+
+ result.put(bytes);
+ }
+
+
+ private byte[] readNBytes(InputStream stream, int length) {
+ byte[] bytes = new byte[length];
+
+ int readBytes = 0;
+ while (readBytes < length) {
+ try {
+ readBytes+=stream.read(bytes, readBytes, length-readBytes);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return bytes;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java
new file mode 100644
index 0000000..37269fd
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/BufferAccessor.java
@@ -0,0 +1,55 @@
+package fr.radi3nt.gltf.data.buffer.accessor;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+
+import java.nio.ByteBuffer;
+
+public class BufferAccessor {
+
+ private final int bufferView;
+ private final GlTFComponentType componentType;
+ private final GlTFAccessorType type;
+ private final int count;
+
+ private final float[] min;
+ private final float[] max;
+
+ public BufferAccessor(int bufferView, GlTFComponentType componentType, GlTFAccessorType type, int count, float[] min, float[] max) {
+ this.bufferView = bufferView;
+ this.componentType = componentType;
+ this.type = type;
+ this.count = count;
+ this.min = min;
+ this.max = max;
+ }
+
+ public ByteBuffer getBuffer(GlTFResult result) {
+ ByteBuffer buffer = result.bufferViews[bufferView].getBuffer(result);
+ buffer.limit(getByteSize());
+ return buffer;
+ }
+
+ public void getBuffer(GlTFResult result, ByteBuffer buffer) {
+ result.bufferViews[bufferView].getBuffer(result, buffer);
+ }
+
+ public GlTFAccessorType getType() {
+ return type;
+ }
+
+ public int getByteSize() {
+ return count*type.amount()*componentType.bytes();
+ }
+
+ public int getComponentBytes() {
+ return componentType.bytes();
+ }
+
+ public int getComponentCount() {
+ return type.amount();
+ }
+
+ public int getCount() {
+ return count;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java
new file mode 100644
index 0000000..deb79ee
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFAccessorType.java
@@ -0,0 +1,19 @@
+package fr.radi3nt.gltf.data.buffer.accessor;
+
+public enum GlTFAccessorType {
+
+ SCALAR(1),
+ VEC3(3),
+ VEC4(4),
+ MAT4(16);
+
+ private final int amount;
+
+ GlTFAccessorType(int amount) {
+ this.amount = amount;
+ }
+
+ public int amount() {
+ return amount;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java
new file mode 100644
index 0000000..b76333c
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/accessor/GlTFComponentType.java
@@ -0,0 +1,29 @@
+package fr.radi3nt.gltf.data.buffer.accessor;
+
+public enum GlTFComponentType {
+
+ GL_FLOAT(5126, 4),
+ GL_UNSIGNED_BYTE(5121, 1),
+ GL_UNSIGNED_SHORT(5123, 2),
+
+ ;
+
+ private final int id;
+ private final int bytes;
+
+ GlTFComponentType(int id, int bytes) {
+ this.id = id;
+ this.bytes = bytes;
+ }
+
+ public static GlTFComponentType fromId(int componentType) {
+ for (GlTFComponentType value : values()) {
+ if (value.id==componentType) return value;
+ }
+ return null;
+ }
+
+ public int bytes() {
+ return bytes;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java
new file mode 100644
index 0000000..c0698c1
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/buffer/view/BufferView.java
@@ -0,0 +1,30 @@
+package fr.radi3nt.gltf.data.buffer.view;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.buffer.GlTFBuffer;
+
+import java.nio.ByteBuffer;
+
+public class BufferView {
+
+ private final int buffer;
+ private final int length;
+ private final long offset;
+
+ public BufferView(int buffer, int length, long offset) {
+ this.buffer = buffer;
+ this.length = length;
+ this.offset = offset;
+ }
+
+ public ByteBuffer getBuffer(GlTFResult result) {
+ GlTFBuffer currentBuffer = result.buffers[buffer];
+
+ return currentBuffer.read(offset, length);
+ }
+
+ public void getBuffer(GlTFResult result, ByteBuffer resultBuff) {
+ GlTFBuffer currentBuffer = result.buffers[buffer];
+ currentBuffer.read(offset, length, resultBuff);
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java
new file mode 100644
index 0000000..149b5f1
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/GlTFMesh.java
@@ -0,0 +1,20 @@
+package fr.radi3nt.gltf.data.mesh;
+
+public class GlTFMesh {
+
+ private final String name;
+ private final Primitive[] primitives;
+
+ public GlTFMesh(String name, Primitive[] primitives) {
+ this.name = name;
+ this.primitives = primitives;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Primitive[] getPrimitives() {
+ return primitives;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java
new file mode 100644
index 0000000..1d3b41f
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/Primitive.java
@@ -0,0 +1,71 @@
+package fr.radi3nt.gltf.data.mesh;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.attributes.GlTFAttribute;
+import fr.radi3nt.gltf.data.buffer.accessor.BufferAccessor;
+import fr.radi3nt.gltf.data.mesh.material.GlTFMaterial;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+public class Primitive {
+
+ private final Map attributesToAccessors;
+ private final int indicesAccessor;
+ private final int materialSlot;
+
+ public Primitive(Map attributesToAccessors, int indicesAccessor, int materialSlot) {
+ this.attributesToAccessors = attributesToAccessors;
+ this.indicesAccessor = indicesAccessor;
+ this.materialSlot = materialSlot;
+ }
+
+ public ByteBuffer get(GlTFAttribute attributes, GlTFResult result) {
+ BufferAccessor bufferAccessor = getAccessor(attributes, result);
+ return bufferAccessor.getBuffer(result);
+ }
+
+ public void get(GlTFAttribute attributes, GlTFResult result, ByteBuffer buffer) {
+ getAccessor(attributes, result).getBuffer(result, buffer);
+ }
+
+ public int getByteSize(GlTFAttribute attribute, GlTFResult result) {
+ BufferAccessor bufferAccessor = getAccessor(attribute, result);
+ return bufferAccessor.getByteSize();
+ }
+
+ public int getComponentByte(GlTFAttribute attribute, GlTFResult result) {
+ BufferAccessor bufferAccessor = getAccessor(attribute, result);
+ return bufferAccessor.getComponentBytes();
+ }
+
+ public int getComponentCount(GlTFAttribute attribute, GlTFResult result) {
+ BufferAccessor bufferAccessor = getAccessor(attribute, result);
+ return bufferAccessor.getComponentCount();
+ }
+
+ public int getCount(GlTFAttribute attribute, GlTFResult result) {
+ BufferAccessor bufferAccessor = getAccessor(attribute, result);
+ return bufferAccessor.getCount();
+ }
+
+ private BufferAccessor getAccessor(GlTFAttribute attribute, GlTFResult result) {
+ int accessor = attributesToAccessors.get(attribute.getId());
+ return result.bufferAccessors[accessor];
+ }
+
+ public ByteBuffer getIndices(GlTFResult result) {
+ return result.bufferAccessors[indicesAccessor].getBuffer(result);
+ }
+
+ public int getCount(GlTFResult result) {
+ return result.bufferAccessors[indicesAccessor].getCount();
+ }
+
+ public GlTFMaterial getMaterial(GlTFResult result) {
+ if (materialSlot==-1)
+ return null;
+ return result.materials[materialSlot];
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java
new file mode 100644
index 0000000..77369e4
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterial.java
@@ -0,0 +1,14 @@
+package fr.radi3nt.gltf.data.mesh.material;
+
+public class GlTFMaterial {
+
+ private final String name;
+
+ public GlTFMaterial(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java
new file mode 100644
index 0000000..883fb3a
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/mesh/material/GlTFMaterialIndexer.java
@@ -0,0 +1,9 @@
+package fr.radi3nt.gltf.data.mesh.material;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+
+public interface GlTFMaterialIndexer {
+
+ int getIndex(GlTFMaterial material, GlTFResult result);
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java
new file mode 100644
index 0000000..76c10a6
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFAbstractNode.java
@@ -0,0 +1,29 @@
+package fr.radi3nt.gltf.data.scene;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+
+public class GlTFAbstractNode {
+
+ private final String name;
+ private final int[] children;
+
+ public GlTFAbstractNode(String name, int[] children) {
+ this.name = name;
+ this.children = children;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public GlTFNode[] getChildren(GlTFResult result) {
+ if (this.children==null)
+ return new GlTFNode[0];
+
+ GlTFNode[] children = new GlTFNode[this.children.length];
+ for (int i = 0; i < children.length; i++) {
+ children[i] = result.nodes[this.children[i]];
+ }
+ return children;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java
new file mode 100644
index 0000000..fa680ec
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFNode.java
@@ -0,0 +1,39 @@
+package fr.radi3nt.gltf.data.scene;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.mesh.GlTFMesh;
+import fr.radi3nt.gltf.data.skins.GlTFSkin;
+
+public class GlTFNode extends GlTFAbstractNode {
+
+ private final GlTFTransform localTransform;
+
+ private final int meshIndex;
+ private final int skinIndex;
+
+ public GlTFNode(String name, int[] children, GlTFTransform localTransform, int meshIndex, int skinIndex) {
+ super(name, children);
+ this.localTransform = localTransform;
+ this.meshIndex = meshIndex;
+ this.skinIndex = skinIndex;
+ }
+
+ public GlTFTransform getLocalTransform() {
+ return localTransform;
+ }
+
+ public GlTFMesh getMesh(GlTFResult result) {
+ if (meshIndex==-1)
+ return null;
+ return result.meshes[meshIndex];
+ }
+
+ public int getMeshIndex() {
+ return meshIndex;
+ }
+
+ public GlTFSkin getSkin(GlTFResult result) {
+ return result.skins[skinIndex];
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java
new file mode 100644
index 0000000..577da9c
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFScene.java
@@ -0,0 +1,8 @@
+package fr.radi3nt.gltf.data.scene;
+
+public class GlTFScene extends GlTFAbstractNode {
+
+ public GlTFScene(String name, int[] children) {
+ super(name, children);
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java
new file mode 100644
index 0000000..3d6353e
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/scene/GlTFTransform.java
@@ -0,0 +1,97 @@
+package fr.radi3nt.gltf.data.scene;
+
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+import fr.radi3nt.json.JsonValue;
+import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4;
+import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4;
+import fr.radi3nt.maths.components.advanced.quaternions.ComponentsQuaternion;
+import fr.radi3nt.maths.components.advanced.quaternions.Quaternion;
+import fr.radi3nt.maths.components.vectors.Vector3f;
+import fr.radi3nt.maths.components.vectors.implementations.SimpleVector3f;
+
+import java.util.function.Supplier;
+
+public class GlTFTransform {
+
+ private final Vector3f translation;
+ private final Quaternion rotation;
+ private final Vector3f scale;
+
+ public GlTFTransform(Vector3f translation, Quaternion rotation, Vector3f scale) {
+ this.translation = translation;
+ this.rotation = rotation;
+ this.scale = scale;
+ }
+
+ public Matrix4x4 toMatrix() {
+ Matrix4x4 result = ArrayMatrix4x4.newIdentity();
+ result.quaternionRotation(rotation);
+ result.translation(translation);
+ result.scalar(scale);
+ return result;
+ }
+
+ public Vector3f transform(Vector3f original) {
+ Vector3f result = original.duplicate();
+ result.mul(scale);
+ rotation.transform(result);
+ result.add(translation);
+ return result;
+ }
+
+ public Vector3f transformOrientation(Vector3f original) {
+ Vector3f result = original.duplicate();
+ rotation.transform(result);
+ return result;
+ }
+
+ public Vector3f getTranslation() {
+ return translation;
+ }
+
+ public Quaternion getRotation() {
+ return rotation;
+ }
+
+ public Vector3f getScale() {
+ return scale;
+ }
+
+ public static GlTFTransform parse(JsonObject nodeJson) {
+ Vector3f translation = parseTranslation(nodeJson);
+ Quaternion rotation = parseRotation(nodeJson);
+ Vector3f scale = parseScale(nodeJson);
+
+ return new GlTFTransform(translation, rotation, scale);
+ }
+
+ private static Vector3f parseScale(JsonObject nodeJson) {
+ JsonValue value = nodeJson.get("scale");
+ return parseVector(value, () -> new SimpleVector3f(1f, 1f, 1f));
+ }
+
+ private static Quaternion parseRotation(JsonObject nodeJson) {
+ JsonValue value = nodeJson.get("rotation");
+ if (value == null) {
+ return ComponentsQuaternion.zero();
+ }
+
+ JsonArray valueArray = value.asArray();
+ return new ComponentsQuaternion(valueArray.get(0).asFloat(), valueArray.get(1).asFloat(), valueArray.get(2).asFloat(), valueArray.get(3).asFloat());
+ }
+
+ private static Vector3f parseTranslation(JsonObject nodeJson) {
+ JsonValue value = nodeJson.get("translation");
+ return parseVector(value, SimpleVector3f::new);
+ }
+
+ private static Vector3f parseVector(JsonValue value, Supplier defaultVec) {
+ if (value == null) {
+ return defaultVec.get();
+ }
+
+ JsonArray valueArray = value.asArray();
+ return new SimpleVector3f(valueArray.get(0).asFloat(), valueArray.get(1).asFloat(), valueArray.get(2).asFloat());
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java b/glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java
new file mode 100644
index 0000000..0c52693
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/data/skins/GlTFSkin.java
@@ -0,0 +1,50 @@
+package fr.radi3nt.gltf.data.skins;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.scene.GlTFNode;
+import fr.radi3nt.maths.components.advanced.matrix.ArrayMatrix4x4;
+import fr.radi3nt.maths.components.advanced.matrix.Matrix4x4;
+
+import java.nio.ByteBuffer;
+
+public class GlTFSkin {
+
+ private final String name;
+ private final int inverseBindMatricesAccessorIndex;
+ private final int[] joints;
+
+ public GlTFSkin(String name, int inverseBindMatricesAccessorIndex, int[] joints) {
+ this.name = name;
+ this.inverseBindMatricesAccessorIndex = inverseBindMatricesAccessorIndex;
+ this.joints = joints;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public GlTFNode[] getJoints(GlTFResult result) {
+ GlTFNode[] nodes = new GlTFNode[joints.length];
+ for (int i = 0; i < joints.length; i++) {
+ nodes[i] = result.nodes[joints[i]];
+ }
+ return nodes;
+ }
+
+ public Matrix4x4[] getInverseBindMatrices(GlTFResult result) {
+ ByteBuffer buffer = result.bufferAccessors[inverseBindMatricesAccessorIndex].getBuffer(result);
+ Matrix4x4[] matrices = new Matrix4x4[joints.length];
+ for (int jointIndex = 0; jointIndex < joints.length; jointIndex++) {
+ float[] mat = new float[4*4];
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ float value = buffer.getFloat();
+ mat[i+j*4] = value;
+ }
+ }
+ Matrix4x4 inverseBind = ArrayMatrix4x4.from(mat);
+ matrices[jointIndex] = inverseBind;
+ }
+ return matrices;
+ }
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java
new file mode 100644
index 0000000..222f6c4
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/AccessorsImporter.java
@@ -0,0 +1,58 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.buffer.accessor.BufferAccessor;
+import fr.radi3nt.gltf.data.buffer.accessor.GlTFAccessorType;
+import fr.radi3nt.gltf.data.buffer.accessor.GlTFComponentType;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+import fr.radi3nt.json.JsonValue;
+
+public class AccessorsImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+
+ JsonArray accessorsJson = file.get("accessors").asArray();
+ BufferAccessor[] accessors = new BufferAccessor[accessorsJson.size()];
+ for (int i = 0; i < accessors.length; i++) {
+ JsonObject accessorJson = accessorsJson.get(i).asObject();
+ int bufferView = accessorJson.getInt("bufferView", -1);
+ GlTFComponentType componentType = GlTFComponentType.fromId(accessorJson.getInt("componentType", -1));
+ int count = accessorJson.getInt("count", 0);
+ GlTFAccessorType accessorType = GlTFAccessorType.valueOf(accessorJson.getString("type"));
+
+ float[] min = getMin(accessorJson);
+ float[] max = getMax(accessorJson);
+
+ accessors[i] = new BufferAccessor(bufferView, componentType, accessorType, count, min, max);
+ }
+
+ result.bufferAccessors = accessors;
+ }
+
+ private float[] getMin(JsonObject accessorJson) {
+ JsonValue value = accessorJson.get("min");
+ if (value==null)
+ return null;
+
+ return parseArray(value);
+ }
+
+ private float[] getMax(JsonObject accessorJson) {
+ JsonValue value = accessorJson.get("max");
+ if (value==null)
+ return null;
+
+ return parseArray(value);
+ }
+
+ private static float[] parseArray(JsonValue value) {
+ JsonArray array = value.asArray();
+ float[] floats = new float[array.size()];
+ for (int i = 0; i < array.size(); i++) {
+ floats[i] = array.get(i).asFloat();
+ }
+ return floats;
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java
new file mode 100644
index 0000000..2cbc8b6
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/BuffersImporter.java
@@ -0,0 +1,33 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.file.files.ReadableFile;
+import fr.radi3nt.file.impl.ResourceFile;
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.buffer.GlTFBuffer;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+
+public class BuffersImporter implements GlTFImporter {
+
+ private final String basePath;
+
+ public BuffersImporter(String basePath) {
+ this.basePath = basePath;
+ }
+
+ public void parse(JsonObject file, GlTFResult result) {
+
+ JsonArray buffersJson = file.get("buffers").asArray();
+ GlTFBuffer[] buffers = new GlTFBuffer[buffersJson.size()];
+ for (int i = 0; i < buffersJson.size(); i++) {
+ JsonObject bufferJson = buffersJson.get(i).asObject();
+ long byteLength = bufferJson.getLong("byteLength", 0);
+ ReadableFile uri = new ResourceFile(basePath + "/" + bufferJson.getString("uri"));
+ buffers[i] = new GlTFBuffer(uri, byteLength);
+ }
+
+ result.buffers = buffers;
+
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java
new file mode 100644
index 0000000..94d8b44
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/GlTFImporter.java
@@ -0,0 +1,10 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.json.JsonObject;
+
+public interface GlTFImporter {
+
+ void parse(JsonObject file, GlTFResult result);
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java
new file mode 100644
index 0000000..0cf7d41
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/MaterialsImporter.java
@@ -0,0 +1,25 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.mesh.material.GlTFMaterial;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+
+public class MaterialsImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+ if (file.get("materials")==null)
+ return;
+
+ JsonArray materialsJson = file.get("materials").asArray();
+ GlTFMaterial[] materials = new GlTFMaterial[materialsJson.size()];
+ for (int i = 0; i < materialsJson.size(); i++) {
+ JsonObject materialJson = materialsJson.get(i).asObject();
+ String name = materialJson.getString("name", "unnamed");
+ materials[i] = new GlTFMaterial(name);
+ }
+
+ result.materials = materials;
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java
new file mode 100644
index 0000000..48c94d7
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/MeshesImporter.java
@@ -0,0 +1,46 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.attributes.GlTFAttribute;
+import fr.radi3nt.gltf.data.attributes.StringGLTFAttribute;
+import fr.radi3nt.gltf.data.mesh.GlTFMesh;
+import fr.radi3nt.gltf.data.mesh.Primitive;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MeshesImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+ JsonArray meshesJson = file.get("meshes").asArray();
+ GlTFMesh[] meshes = new GlTFMesh[meshesJson.size()];
+ for (int i = 0; i < meshesJson.size(); i++) {
+ JsonObject meshJson = meshesJson.get(i).asObject();
+ String name = meshJson.getString("name", "unnamed");
+
+ JsonArray primitivesJson = meshJson.get("primitives").asArray();
+ Primitive[] primitives = new Primitive[primitivesJson.size()];
+ for (int j = 0; j < primitivesJson.size(); j++) {
+ JsonObject primitiveJson = primitivesJson.get(j).asObject();
+ JsonObject attributes = primitiveJson.get("attributes").asObject();
+ Map attributesMap = new HashMap<>();
+ for (JsonObject.Member attribute : attributes) {
+ int accessorIndex = attribute.getValue().asInt();
+ attributesMap.put(attribute.getName(), accessorIndex);
+ }
+
+ int indicesIndex = primitiveJson.getInt("indices", -1);
+ int material = primitiveJson.getInt("material", -1);
+
+ primitives[j] = new Primitive(attributesMap, indicesIndex, material);
+ }
+
+ meshes[i] = new GlTFMesh(name, primitives);
+ }
+
+ result.meshes = meshes;
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java
new file mode 100644
index 0000000..3d2bb5d
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/NodesImporter.java
@@ -0,0 +1,44 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.scene.GlTFNode;
+import fr.radi3nt.gltf.data.scene.GlTFTransform;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+import fr.radi3nt.json.JsonValue;
+
+public class NodesImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+ JsonArray nodesJsonArray = file.get("nodes").asArray();
+ GlTFNode[] nodes = new GlTFNode[nodesJsonArray.size()];
+ for (int i = 0; i < nodesJsonArray.size(); i++) {
+ JsonObject nodeJson = nodesJsonArray.get(i).asObject();
+
+ String name = nodeJson.getString("name", "undefined");
+ int meshIndex = nodeJson.getInt("mesh", -1);
+ int skinIndex = nodeJson.getInt("skin", -1);
+
+ int[] children = getChildrenOrNull(nodeJson);
+ GlTFTransform transform = GlTFTransform.parse(nodeJson);
+
+ nodes[i] = new GlTFNode(name, children, transform, meshIndex, skinIndex);
+ }
+
+ result.nodes = nodes;
+ }
+
+ private static int[] getChildrenOrNull(JsonObject nodeJson) {
+ JsonValue childrenJson = nodeJson.get("children");
+ if (childrenJson == null) {
+ return null;
+ }
+ JsonArray childrenJsonArray = childrenJson.asArray();
+ int[] children = new int[childrenJsonArray.size()];
+ for (int j = 0; j < childrenJsonArray.size(); j++) {
+ children[j] = childrenJsonArray.get(j).asInt();
+ }
+ return children;
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java
new file mode 100644
index 0000000..7cadc94
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/ScenesImporter.java
@@ -0,0 +1,29 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.scene.GlTFScene;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+
+public class ScenesImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+ JsonArray scenesJson = file.get("scenes").asArray();
+ GlTFScene[] scenes = new GlTFScene[scenesJson.size()];
+ for (int i = 0; i < scenesJson.size(); i++) {
+ JsonObject sceneJson = scenesJson.get(i).asObject();
+ String sceneName = sceneJson.asObject().getString("name");
+ JsonArray nodesJson = sceneJson.asObject().get("nodes").asArray();
+ int[] nodes = new int[nodesJson.size()];
+ for (int j = 0; j < nodesJson.size(); j++) {
+ nodes[j] = nodesJson.get(j).asInt();
+ }
+
+ GlTFScene currentScene = new GlTFScene(sceneName, nodes);
+ scenes[i] = currentScene;
+ }
+
+ result.scenes = scenes;
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java
new file mode 100644
index 0000000..9e93d01
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/SkinsImporter.java
@@ -0,0 +1,39 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.skins.GlTFSkin;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+import fr.radi3nt.json.JsonValue;
+
+public class SkinsImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+
+ JsonValue skinsValue = file.get("skins");
+ if (skinsValue==null)
+ return;
+ JsonArray skinsJson = skinsValue.asArray();
+
+ GlTFSkin[] skins = new GlTFSkin[skinsJson.size()];
+ for (int i = 0; i < skins.length; i++) {
+ JsonObject skinJson = skinsJson.get(i).asObject();
+
+ String name = skinJson.getString("name", "unnamed");
+
+ JsonArray jointsJson = skinJson.get("joints").asArray();
+ int[] joints = new int[jointsJson.size()];
+ for (int j = 0; j < joints.length; j++) {
+ joints[j] = jointsJson.get(j).asInt();
+ }
+
+ int inverseBindMatrixAccessorIndex = skinJson.get("inverseBindMatrices").asInt();
+
+ skins[i] = new GlTFSkin(name, inverseBindMatrixAccessorIndex, joints);
+ }
+
+ result.skins = skins;
+
+ }
+
+}
diff --git a/glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java b/glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java
new file mode 100644
index 0000000..bbc44c7
--- /dev/null
+++ b/glTF/src/main/java/fr/radi3nt/gltf/importer/ViewImporter.java
@@ -0,0 +1,26 @@
+package fr.radi3nt.gltf.importer;
+
+import fr.radi3nt.gltf.data.GlTFResult;
+import fr.radi3nt.gltf.data.buffer.view.BufferView;
+import fr.radi3nt.json.JsonArray;
+import fr.radi3nt.json.JsonObject;
+
+public class ViewImporter implements GlTFImporter {
+
+ public void parse(JsonObject file, GlTFResult result) {
+
+ JsonArray bufferViewsJson = file.get("bufferViews").asArray();
+ BufferView[] bufferViews = new BufferView[bufferViewsJson.size()];
+ for (int i = 0; i < bufferViewsJson.size(); i++) {
+ JsonObject viewJson = bufferViewsJson.get(i).asObject();
+ int buffer = viewJson.getInt("buffer", -1);
+ int byteLength = viewJson.getInt("byteLength", 0);
+ long byteOffset = viewJson.getLong("byteOffset", 0);
+ bufferViews[i] = new BufferView(buffer, byteLength, byteOffset);
+ }
+
+ result.bufferViews = bufferViews;
+
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index ae7bb1b..3f1464c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,14 @@
NoiseHelper
BehaviorTree
LanguageHelperV2
+ DataStructures
+ SplineHelper
+ InverseKinematics
+ Pathfinding
+ AnimationsImport
+ Animations
+ glTF
+ Armature