SimpleJavaEngine/src/main/java/speiger/src/coreengine/math/misc/FacingList.java

313 lines
6.6 KiB
Java

package speiger.src.coreengine.math.misc;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Set;
import java.util.StringJoiner;
import java.util.function.Predicate;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.MathUtils;
import speiger.src.coreengine.math.misc.Facing.Axis;
import speiger.src.coreengine.math.vector.ints.Vec2i;
public final class FacingList implements Iterable<Facing>, Predicate<Facing>
{
static final FacingList[] FACINGS = createArray();
public static final FacingList EMPTY = ofNumber(0);
public static final FacingList NORTH = ofFacings(Facing.NORTH);
public static final FacingList EAST = ofFacings(Facing.EAST);
public static final FacingList SOUTH = ofFacings(Facing.SOUTH);
public static final FacingList WEST = ofFacings(Facing.WEST);
public static final FacingList NORTH_EAST = ofFacings(Facing.NORTH, Facing.EAST);
public static final FacingList SOUTH_EAST = ofFacings(Facing.EAST, Facing.SOUTH);
public static final FacingList SOUTH_WEST = ofFacings(Facing.SOUTH, Facing.WEST);
public static final FacingList NORTH_WEST = ofFacings(Facing.WEST, Facing.NORTH);
public static final FacingList VERTICAL = ofFacings(Facing.NORTH, Facing.SOUTH);
public static final FacingList HORIZONTAL = ofFacings(Facing.EAST, Facing.WEST);
public static final FacingList ALL = ofFacings(Facing.NORTH, Facing.SOUTH, Facing.EAST, Facing.WEST);
final byte code;
final byte next;
final byte opposite;
final byte prev;
final byte count;
final Vec2i offset;
final Facing[] array;
private FacingList(int initCode)
{
code = (byte)MathUtils.clamp(0, 15, initCode);
Vec2i pos = Vec2i.mutable();
ObjectList<Facing> facings = new ObjectArrayList<Facing>();
for(int i = 0;i<4;i++)
{
if((code & 1 << i) != 0)
{
pos.add(Facing.byIndex(i).getOffset());
facings.add(Facing.byIndex(i));
}
}
int[] data = new int[3];
for(int i = 0,m=facings.size();i<m;i++)
{
Facing face = facings.get(i);
data[0] |= 1 << face.forward().getIndex();
data[1] |= 1 << face.opposite().getIndex();
data[2] |= 1 << face.backwards().getIndex();
}
next = (byte)MathUtils.clamp(0, 15, data[0]);
opposite = (byte)MathUtils.clamp(0, 15, data[1]);
prev = (byte)MathUtils.clamp(0, 15, data[2]);
offset = pos.asImmutable();
count = (byte)facings.size();
array = facings.toArray(new Facing[facings.size()]);
}
public static FacingList ofFacing(Facing facing)
{
return FACINGS[1 << facing.getIndex()];
}
public static FacingList ofFacings(Facing... facings)
{
return FACINGS[toNumber(facings)];
}
public static FacingList ofFlags(boolean[] facings)
{
return FACINGS[toNumber(facings)];
}
public static FacingList ofNumber(int value)
{
return FACINGS[value & 15];
}
public static FacingList ofAxis(Axis axis)
{
return FACINGS[axis.getCode()];
}
public static FacingList fromVec(Vec2i value)
{
value = value.clamp(-1, 1);
for(int i = 0;i<16;i++)
{
if(FACINGS[i].getOffset().equals(value))
{
return FACINGS[i];
}
}
return FACINGS[0];
}
public Set<Facing> toFacings()
{
return isEmpty() ? EnumSet.noneOf(Facing.class) : EnumSet.copyOf(ObjectArrayList.wrap(array));
}
public boolean[] toFlags()
{
return toFlags(array);
}
public int getRotation()
{
switch(count)
{
case 1: return array[0].getRotation();
case 2: return array[0].getRotation(array[1]);
default: return 0;
}
}
public FacingList rotate(int amount)
{
switch(amount & 3)
{
case 1: return FACINGS[next];
case 2: return FACINGS[opposite];
case 3: return FACINGS[prev];
default: return this;
}
}
public FacingList invert()
{
return FACINGS[15 - code];
}
public FacingList opposite()
{
return FACINGS[opposite];
}
public FacingList add(Facing facing)
{
return FACINGS[code | (1 << facing.getIndex())];
}
public FacingList add(FacingList facings)
{
return FACINGS[code | facings.code];
}
public FacingList remove(Facing facing)
{
return FACINGS[code & ~(1 << facing.getIndex())];
}
public FacingList remove(FacingList facings)
{
return FACINGS[code & ~facings.code];
}
public boolean contains(Facing direction)
{
return (code & 1 << direction.getIndex()) != 0;
}
public boolean contains(FacingList facings)
{
return (code & facings.code) == facings.code;
}
public boolean containsAny(FacingList facings)
{
return (code & facings.code) != 0;
}
public boolean notContains(Facing direction)
{
return (code & 1 << direction.getIndex()) == 0;
}
public boolean notContains(FacingList facings)
{
return (code & facings.code) != facings.code;
}
public FacingList flipFacing(Facing facing)
{
return contains(facing) ? remove(facing).add(facing.opposite()) : this;
}
public FacingList flipAxis(Axis axis)
{
FacingList result = this;
for(int i = 0,m=array.length;i<m;i++)
{
if(array[i].getAxis() == axis)
{
result = result.remove(array[i]).add(array[i].opposite());
}
}
return result;
}
public Vec2i getOffset()
{
return offset;
}
public Facing getFacing(int index)
{
return array[index];
}
public int getCode()
{
return code;
}
public int size()
{
return count;
}
public boolean isEmpty()
{
return code == 0;
}
public boolean isFull()
{
return code == 15;
}
@Override
public String toString()
{
StringJoiner joiner = new StringJoiner(",", "[", "]");
for(int i = 0,m=array.length;i<m;i++)
{
joiner.add(array[i].getName());
}
return joiner.toString();
}
@Override
public boolean test(Facing t)
{
return (code & 1 << t.getIndex()) != 0;
}
@Override
public Iterator<Facing> iterator()
{
return new Iterator<Facing>(){
int index = 0;
@Override
public boolean hasNext()
{
return index < size();
}
@Override
public Facing next()
{
return array[index++];
}
};
}
public static int toNumber(Facing...facings)
{
int value = 0;
for(int i = 0,m=facings.length;i<m;i++)
{
value |= (1 << facings[i].getIndex());
}
return value & 15;
}
public static int toNumber(boolean[] facings)
{
return (facings[0] ? 1 : 0) << 0 | (facings[1] ? 1 : 0) << 1 | (facings[2] ? 1 : 0) << 2 | (facings[3] ? 1 : 0) << 3;
}
public static boolean[] toFlags(Facing...facings)
{
boolean[] array = new boolean[4];
for(int i = 0,m=facings.length;i<m;i++)
{
array[facings[i].getIndex()] = true;
}
return array;
}
private static FacingList[] createArray()
{
FacingList[] facings = new FacingList[16];
for(int i = 0;i<16;i++)
{
facings[i] = new FacingList(i);
}
return facings;
}
}