Added RelRelation and RelFace; added discrete up vector to GravityModel
This commit is contained in:
parent
acef9d32df
commit
10d271059c
@ -39,6 +39,40 @@ public class VectorUtil {
|
|||||||
X, Y, Z, W;
|
X, Y, Z, W;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static enum SignedAxis {
|
||||||
|
POS_X(Axis.X, +1),
|
||||||
|
NEG_X(Axis.X, -1),
|
||||||
|
POS_Y(Axis.Y, +1),
|
||||||
|
NEG_Y(Axis.Y, -1),
|
||||||
|
POS_Z(Axis.Z, +1),
|
||||||
|
NEG_Z(Axis.Z, -1),
|
||||||
|
POS_W(Axis.W, +1),
|
||||||
|
NEG_W(Axis.W, -1);
|
||||||
|
|
||||||
|
private final Axis axis;
|
||||||
|
private final boolean isPositive;
|
||||||
|
|
||||||
|
private SignedAxis(Axis axis, int sign) {
|
||||||
|
this.axis = axis;
|
||||||
|
this.isPositive = (sign == +1 ? true : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the axis
|
||||||
|
*/
|
||||||
|
public Axis getAxis() {
|
||||||
|
return axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPositive() {
|
||||||
|
return isPositive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSign() {
|
||||||
|
return isPositive ? +1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void iterateCuboid(
|
public static void iterateCuboid(
|
||||||
int x0,
|
int x0,
|
||||||
int y0,
|
int y0,
|
||||||
|
@ -20,15 +20,33 @@ package ru.windcorp.progressia.common.world;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gravity model specifies the gravitational acceleration field. A gravity model
|
* Gravity model specifies the gravitational acceleration field, the up
|
||||||
* may be queried for the vector of gravitational acceleration that should
|
* direction field and the discrete up direction field.
|
||||||
* affect an object. This vector is, generally speaking, a function of space:
|
* <p>
|
||||||
* gravity in two different locations may vary. Gravity may also be a zero
|
* A gravity model may be queried for the vector of gravitational acceleration
|
||||||
* vector.
|
* that should affect an object. This vector is, generally speaking, a function
|
||||||
|
* of space: gravity in two different locations may vary. Gravity may also be a
|
||||||
|
* zero vector.
|
||||||
|
* <p>
|
||||||
|
* The vector of gravitational acceleration defines the up direction. Up vector
|
||||||
|
* is defined as the additive inverse of the normalized gravitational
|
||||||
|
* acceleration vector or {@code (0; 0; 0)} if there is no gravity.
|
||||||
|
* <p>
|
||||||
|
* Separately from the gravitational acceleration and the up vectors, a
|
||||||
|
* <em>discrete up</em> vector field is specified by a gravity model. This field
|
||||||
|
* is defined for each chunk uniquely and may only take the value of one of the
|
||||||
|
* six {@linkplain AbsFace absolute directions}. This vector specifies the
|
||||||
|
* rotation of blocks, tiles and other objects that may not have a
|
||||||
|
* non-axis-aligned direction. Discrete up vector must be specified even for
|
||||||
|
* chunks that have a zero or an ambiguous up direction. Although discrete up
|
||||||
|
* direction is not technically linked to the up direction, is it expected by
|
||||||
|
* the players that they generally align.
|
||||||
*
|
*
|
||||||
* @author javapony
|
* @author javapony
|
||||||
*/
|
*/
|
||||||
@ -77,11 +95,54 @@ public abstract class GravityModel extends Namespaced {
|
|||||||
*/
|
*/
|
||||||
public Vec3 getUp(Vec3 pos, Vec3 output) {
|
public Vec3 getUp(Vec3 pos, Vec3 output) {
|
||||||
output = getGravity(pos, output);
|
output = getGravity(pos, output);
|
||||||
if (output.any())
|
|
||||||
|
if (output.any()) {
|
||||||
output.normalize().negate();
|
output.normalize().negate();
|
||||||
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the discrete up vector for the chunk at the specified
|
||||||
|
* coordinates.
|
||||||
|
*
|
||||||
|
* @param chunkPos the coordinates of chunk to compute discrete up at
|
||||||
|
* @return an {@link AbsFace} that corresponds to the up direction in the
|
||||||
|
* specified chunk. Never {@code null}.
|
||||||
|
*/
|
||||||
|
public AbsFace getDiscreteUp(Vec3i chunkPos) {
|
||||||
|
Objects.requireNonNull(chunkPos, "chunkPos");
|
||||||
|
|
||||||
|
final AbsFace result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = doGetDiscreteUp(chunkPos);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw CrashReports.report(
|
||||||
|
e,
|
||||||
|
"%s failed to compute discrete up at (%d; %d; %d)",
|
||||||
|
this,
|
||||||
|
chunkPos.x,
|
||||||
|
chunkPos.y,
|
||||||
|
chunkPos.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
throw CrashReports.report(
|
||||||
|
null,
|
||||||
|
"%s has computed null as the discrete up at (%d; %d; %d). This is forbidden.",
|
||||||
|
this,
|
||||||
|
chunkPos.x,
|
||||||
|
chunkPos.y,
|
||||||
|
chunkPos.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the gravitational acceleration vector at the provided location.
|
* Computes the gravitational acceleration vector at the provided location.
|
||||||
* Actual computation of gravity is delegated to this method by the other
|
* Actual computation of gravity is delegated to this method by the other
|
||||||
@ -93,4 +154,16 @@ public abstract class GravityModel extends Namespaced {
|
|||||||
*/
|
*/
|
||||||
protected abstract void doGetGravity(Vec3 pos, Vec3 output);
|
protected abstract void doGetGravity(Vec3 pos, Vec3 output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the discrete up vector for the chunk at the specified
|
||||||
|
* coordinates. A direction must be assigned under any circumstances. Actual
|
||||||
|
* computation of discrete up is delegated to this method by the other
|
||||||
|
* methods in this class.
|
||||||
|
*
|
||||||
|
* @param chunkPos the coordinates of chunk to compute discrete up at
|
||||||
|
* @return an {@link AbsFace} that corresponds to the up direction in the
|
||||||
|
* specified chunk. Never {@code null}.
|
||||||
|
*/
|
||||||
|
protected abstract AbsFace doGetDiscreteUp(Vec3i chunkPos);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,12 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.common.world.rels;
|
package ru.windcorp.progressia.common.world.rels;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
import glm.vec._3.i.Vec3i;
|
import glm.vec._3.i.Vec3i;
|
||||||
|
|
||||||
public final class AbsFace extends AbsRelation {
|
public final class AbsFace extends AbsRelation {
|
||||||
@ -88,6 +91,124 @@ public final class AbsFace extends AbsRelation {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the provided vector to one of {@link AbsFace}s. The returned face
|
||||||
|
* is pointing in the same general direction as the provided vector. The
|
||||||
|
* result is undefined for arguments where two largest in absolute values
|
||||||
|
* coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector
|
||||||
|
* the result is {@code null}. Infinite vectors are handled correctly.
|
||||||
|
*
|
||||||
|
* @param vector the vector to round
|
||||||
|
* @return the face most adequately describing the provided vector, or
|
||||||
|
* {@code null} iff {@code vector.x = vector.y = vector.z = 0}
|
||||||
|
* @throws IllegalArgumentException if one of the coordinates is a NaN
|
||||||
|
*/
|
||||||
|
public static AbsFace roundToFace(Vec3 vector) {
|
||||||
|
Objects.requireNonNull(vector, "vector");
|
||||||
|
return roundToFace(vector.x, vector.y, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the provided vector to one of {@link AbsFace}s. The returned face
|
||||||
|
* is pointing in the same general direction as the provided vector. The
|
||||||
|
* result is undefined for arguments where two largest in absolute values
|
||||||
|
* coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector
|
||||||
|
* the result is {@code null}. Infinite arguments are handled correctly.
|
||||||
|
*
|
||||||
|
* @param x the X coordinate
|
||||||
|
* @param y the Y coordinate
|
||||||
|
* @param z the Z coordinate
|
||||||
|
* @return the face most adequately describing the provided vector, or
|
||||||
|
* {@code null} iff {@code x = y = z = 0}
|
||||||
|
* @throws IllegalArgumentException if one of the coordinates is a NaN
|
||||||
|
*/
|
||||||
|
public static AbsFace roundToFace(float x, float y, float z) {
|
||||||
|
if (x == 0 && y == 0 && z == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Float.isNaN(x) || Float.isNaN(y) || Float.isNaN(z)) {
|
||||||
|
throw new IllegalArgumentException("Vector contains NaN: (" + x + "; " + y + "; " + z + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following code handles infinite x, y or z properly
|
||||||
|
|
||||||
|
float absX = Math.abs(x);
|
||||||
|
float absY = Math.abs(y);
|
||||||
|
float absZ = Math.abs(z);
|
||||||
|
|
||||||
|
if (absX > absY) {
|
||||||
|
if (absX > absZ) {
|
||||||
|
return x > 0 ? POS_X : NEG_X;
|
||||||
|
} else {
|
||||||
|
// Z is the answer; exit decision tree
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (absY > absZ) {
|
||||||
|
return y > 0 ? POS_Y : NEG_Y;
|
||||||
|
} else {
|
||||||
|
// Z is the answer; exit decision tree
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return z > 0 ? POS_Z : NEG_Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the provided vector to one of {@link AbsFace}s. The returned face
|
||||||
|
* is pointing in the same general direction as the provided vector. The
|
||||||
|
* result is undefined for arguments where two largest in absolute values
|
||||||
|
* coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector
|
||||||
|
* the result is {@code null}.
|
||||||
|
*
|
||||||
|
* @param vector the vector to round
|
||||||
|
* @return the face most adequately describing the provided vector, or
|
||||||
|
* {@code null} iff {@code vector.x = vector.y = vector.z = 0}
|
||||||
|
*/
|
||||||
|
public static AbsFace roundToFace(Vec3i vector) {
|
||||||
|
Objects.requireNonNull(vector, "vector");
|
||||||
|
return roundToFace(vector.x, vector.y, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the provided vector to one of {@link AbsFace}s. The returned face
|
||||||
|
* is pointing in the same general direction as the provided vector. The
|
||||||
|
* result is undefined for arguments where two largest in absolute values
|
||||||
|
* coordinates are equal (e.g. for {@code (5; -5; 2)}). For a zero vector
|
||||||
|
* the result is {@code null}.
|
||||||
|
*
|
||||||
|
* @param x the X coordinate
|
||||||
|
* @param y the Y coordinate
|
||||||
|
* @param z the Z coordinate
|
||||||
|
* @return the face most adequately describing the provided vector, or
|
||||||
|
* {@code null} iff {@code x = y = z = 0}
|
||||||
|
*/
|
||||||
|
public static AbsFace roundToFace(int x, int y, int z) {
|
||||||
|
if (x == 0 && y == 0 && z == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int absX = Math.abs(x);
|
||||||
|
int absY = Math.abs(y);
|
||||||
|
int absZ = Math.abs(z);
|
||||||
|
|
||||||
|
if (absX > absY) {
|
||||||
|
if (absX > absZ) {
|
||||||
|
return x > 0 ? POS_X : NEG_X;
|
||||||
|
} else {
|
||||||
|
// Z is the answer; exit decision tree
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (absY > absZ) {
|
||||||
|
return y > 0 ? POS_Y : NEG_Y;
|
||||||
|
} else {
|
||||||
|
// Z is the answer; exit decision tree
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return z > 0 ? POS_Z : NEG_Z;
|
||||||
|
}
|
||||||
|
|
||||||
private static int nextId = 0;
|
private static int nextId = 0;
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
@ -39,6 +39,10 @@ public abstract class BlockRelation {
|
|||||||
return resolve(up).getNormalized();
|
return resolve(up).getNormalized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Vec3i getSample() {
|
||||||
|
return getVector(AbsFace.POS_Z);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the distance between the source and destination blocks, as
|
* Returns the distance between the source and destination blocks, as
|
||||||
* defined by the Euclidean space. Your everyday distance.
|
* defined by the Euclidean space. Your everyday distance.
|
||||||
@ -46,7 +50,7 @@ public abstract class BlockRelation {
|
|||||||
* @return square root of the sum of the squares of the coordinates
|
* @return square root of the sum of the squares of the coordinates
|
||||||
*/
|
*/
|
||||||
public float getEuclideanDistance() {
|
public float getEuclideanDistance() {
|
||||||
return getVector(AbsFace.POS_Z).length();
|
return getSample().length();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,7 +63,7 @@ public abstract class BlockRelation {
|
|||||||
* @return the sum of the absolute values of the coordinates
|
* @return the sum of the absolute values of the coordinates
|
||||||
*/
|
*/
|
||||||
public int getManhattanDistance() {
|
public int getManhattanDistance() {
|
||||||
Vec3i vector = getVector(AbsFace.POS_Z);
|
Vec3i vector = getSample();
|
||||||
return abs(vector.x) + abs(vector.y) + abs(vector.z);
|
return abs(vector.x) + abs(vector.y) + abs(vector.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +75,7 @@ public abstract class BlockRelation {
|
|||||||
* @return the maximum of the absolute values of the coordinates
|
* @return the maximum of the absolute values of the coordinates
|
||||||
*/
|
*/
|
||||||
public int getChebyshevDistance() {
|
public int getChebyshevDistance() {
|
||||||
Vec3i vector = getVector(AbsFace.POS_Z);
|
Vec3i vector = getSample();
|
||||||
return max(abs(vector.x), max(abs(vector.y), abs(vector.z)));
|
return max(abs(vector.x), max(abs(vector.y), abs(vector.z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.rels;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
|
|
||||||
|
public class RelFace extends RelRelation {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
public static final RelFace
|
||||||
|
UP = new RelFace( 0, 0, +1, "UP"),
|
||||||
|
DOWN = new RelFace( 0, 0, -1, "DOWN"),
|
||||||
|
NORTH = new RelFace(+1, 0, 0, "NORTH"),
|
||||||
|
SOUTH = new RelFace(-1, 0, 0, "SOUTH"),
|
||||||
|
WEST = new RelFace( 0, +1, 0, "WEST"),
|
||||||
|
EAST = new RelFace( 0, -1, 0, "EAST");
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
private static final ImmutableList<RelFace> ALL_FACES = ImmutableList.of(UP, DOWN, NORTH, SOUTH, WEST, EAST);
|
||||||
|
|
||||||
|
static {
|
||||||
|
link(UP, DOWN);
|
||||||
|
link(NORTH, SOUTH);
|
||||||
|
link(WEST, EAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImmutableList<RelFace> getFaces() {
|
||||||
|
return ALL_FACES;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void link(RelFace a, RelFace b) {
|
||||||
|
a.counterFace = b;
|
||||||
|
b.counterFace = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E> ImmutableMap<RelFace, E> mapToFaces(
|
||||||
|
E up,
|
||||||
|
E down,
|
||||||
|
E north,
|
||||||
|
E south,
|
||||||
|
E west,
|
||||||
|
E east
|
||||||
|
) {
|
||||||
|
return ImmutableMap.<RelFace, E>builderWithExpectedSize(6)
|
||||||
|
.put(UP, up)
|
||||||
|
.put(DOWN, down)
|
||||||
|
.put(NORTH, north)
|
||||||
|
.put(SOUTH, south)
|
||||||
|
.put(WEST, west)
|
||||||
|
.put(EAST, east)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int nextId = 0;
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
private final String name;
|
||||||
|
private RelFace counterFace;
|
||||||
|
|
||||||
|
private RelFace(int x, int y, int z, String name) {
|
||||||
|
super(x, y, z, true);
|
||||||
|
this.id = nextId++;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelFace getCounter() {
|
||||||
|
return counterFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelFace getCounterAndMoveCursor(Vec3i cursor) {
|
||||||
|
cursor.add(getVector());
|
||||||
|
return counterFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getEuclideanDistance() {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChebyshevDistance() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getManhattanDistance() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.rels;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
|
import ru.windcorp.progressia.common.util.VectorUtil;
|
||||||
|
import ru.windcorp.progressia.common.util.VectorUtil.SignedAxis;
|
||||||
|
|
||||||
|
import static ru.windcorp.progressia.common.util.VectorUtil.SignedAxis.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name stands for Relative Relation
|
||||||
|
*/
|
||||||
|
public class RelRelation extends BlockRelation {
|
||||||
|
|
||||||
|
private static class Rotation {
|
||||||
|
private final SignedAxis northDestination;
|
||||||
|
private final SignedAxis westDestination;
|
||||||
|
private final SignedAxis upDestination;
|
||||||
|
|
||||||
|
public Rotation(SignedAxis northDestination, SignedAxis westDestination, SignedAxis upDestination) {
|
||||||
|
this.northDestination = northDestination;
|
||||||
|
this.westDestination = westDestination;
|
||||||
|
this.upDestination = upDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3i apply(Vec3i output, Vec3i input) {
|
||||||
|
if (output == null) {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(output, input.x, northDestination);
|
||||||
|
set(output, input.y, westDestination);
|
||||||
|
set(output, input.z, upDestination);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void set(Vec3i output, int value, SignedAxis axis) {
|
||||||
|
VectorUtil.set(output, axis.getAxis(), axis.isPositive() ? +value : -value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Map<AbsFace, Rotation> TRANSFORMATIONS = AbsFace.mapToFaces(
|
||||||
|
new Rotation(POS_X, POS_Y, POS_Z),
|
||||||
|
new Rotation(POS_X, NEG_Y, NEG_Z),
|
||||||
|
new Rotation(POS_Z, NEG_Y, POS_X),
|
||||||
|
new Rotation(POS_Z, POS_Y, NEG_X),
|
||||||
|
new Rotation(POS_Z, NEG_X, NEG_Y),
|
||||||
|
new Rotation(POS_Z, POS_X, POS_Y)
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Vec3i vector = new Vec3i();
|
||||||
|
private AbsRelation[] resolved = null;
|
||||||
|
|
||||||
|
public RelRelation(int north, int west, int up) {
|
||||||
|
this(north, west, up, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RelRelation(int north, int west, int up, boolean precomputeAllResolutions) {
|
||||||
|
vector.set(north, west, up);
|
||||||
|
|
||||||
|
if (precomputeAllResolutions) {
|
||||||
|
for (AbsFace face : AbsFace.getFaces()) {
|
||||||
|
resolve(face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the relative vector (northward, westward, upward)
|
||||||
|
*/
|
||||||
|
public Vec3i getVector() {
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNorthward() {
|
||||||
|
return vector.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWestward() {
|
||||||
|
return vector.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUpward() {
|
||||||
|
return vector.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSouthward() {
|
||||||
|
return -getNorthward();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEastward() {
|
||||||
|
return -getWestward();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDownward() {
|
||||||
|
return -getUpward();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbsRelation resolve(AbsFace up) {
|
||||||
|
if (resolved == null) {
|
||||||
|
resolved = new AbsRelation[AbsFace.BLOCK_FACE_COUNT];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved[up.getId()] == null) {
|
||||||
|
resolved[up.getId()] = computeResolution(up);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved[up.getId()];
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbsRelation computeResolution(AbsFace up) {
|
||||||
|
return new AbsRelation(TRANSFORMATIONS.get(up).apply(new Vec3i(), vector));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Vec3i getSample() {
|
||||||
|
return getVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,7 +18,9 @@
|
|||||||
package ru.windcorp.progressia.test.gen;
|
package ru.windcorp.progressia.test.gen;
|
||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
|
import glm.vec._3.i.Vec3i;
|
||||||
import ru.windcorp.progressia.common.world.GravityModel;
|
import ru.windcorp.progressia.common.world.GravityModel;
|
||||||
|
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||||
|
|
||||||
public class TestGravityModel extends GravityModel {
|
public class TestGravityModel extends GravityModel {
|
||||||
|
|
||||||
@ -38,4 +40,10 @@ public class TestGravityModel extends GravityModel {
|
|||||||
output.normalize().mul(-9.8f);
|
output.normalize().mul(-9.8f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AbsFace doGetDiscreteUp(Vec3i chunkPos) {
|
||||||
|
AbsFace rounded = AbsFace.roundToFace(chunkPos.x, chunkPos.y, chunkPos.z - 54);
|
||||||
|
return rounded == null ? AbsFace.POS_Z : rounded;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user