You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
6.5 KiB
205 lines
6.5 KiB
using System; |
|
using System.Collections.Immutable; |
|
using System.Text; |
|
using Silk.NET.Maths; |
|
|
|
namespace gaemstone.Bloxel; |
|
|
|
[Flags] |
|
public enum Neighbor : byte |
|
{ |
|
None = 0, |
|
|
|
// FACINGS |
|
East = 0b000011, // +X |
|
West = 0b000010, // -X |
|
Up = 0b001100, // +Y |
|
Down = 0b001000, // -Y |
|
South = 0b110000, // +Z |
|
North = 0b100000, // -Z |
|
|
|
// CARDINALS |
|
SouthEast = South | East, // +X +Z |
|
SouthWest = South | West, // -X +Z |
|
NorthEast = North | East, // +X -Z |
|
NorthWest = North | West, // -X -Z |
|
|
|
// ALL_AXIS_PLANES |
|
UpEast = Up | East , // +X +Y |
|
UpWest = Up | West , // -X +Y |
|
UpSouth = Up | South, // +Z +Y |
|
UpNorth = Up | North, // -Z +Y |
|
|
|
DownEast = Down | East , // +X -Y |
|
DownWest = Down | West , // -X -Y |
|
DownSouth = Down | South, // +Z -Y |
|
DownNorth = Down | North, // -Z -Y |
|
|
|
// ALL |
|
UpSouthEast = Up | South | East, // +X +Y +Z |
|
UpSouthWest = Up | South | West, // -X +Y +Z |
|
UpNorthEast = Up | North | East, // +X +Y -Z |
|
UpNorthWest = Up | North | West, // -X +Y -Z |
|
|
|
DownSouthEast = Down | South | East, // +X -Y +Z |
|
DownSouthWest = Down | South | West, // -X -Y +Z |
|
DownNorthEast = Down | North | East, // +X -Y -Z |
|
DownNorthWest = Down | North | West, // -X -Y -Z |
|
} |
|
|
|
public static class Neighbors |
|
{ |
|
public static readonly ImmutableHashSet<Neighbor> Horizontals |
|
= ImmutableHashSet.Create(Neighbor.East , Neighbor.West , |
|
Neighbor.South, Neighbor.North); |
|
|
|
public static readonly ImmutableHashSet<Neighbor> Verticals |
|
= ImmutableHashSet.Create(Neighbor.Up, Neighbor.Down); |
|
|
|
public static readonly ImmutableHashSet<Neighbor> Facings |
|
= Horizontals.Union(Verticals); |
|
|
|
public static readonly ImmutableHashSet<Neighbor> Cardinals |
|
= Horizontals.Union(new[] { |
|
Neighbor.SouthEast, Neighbor.SouthWest, |
|
Neighbor.NorthEast, Neighbor.NorthWest }); |
|
|
|
public static readonly ImmutableHashSet<Neighbor> AllAxisPlanes |
|
= Facings.Union(new[] { |
|
Neighbor.SouthEast, Neighbor.SouthWest, |
|
Neighbor.NorthEast, Neighbor.NorthWest, |
|
Neighbor.UpEast , Neighbor.UpWest , |
|
Neighbor.UpSouth , Neighbor.UpNorth , |
|
Neighbor.DownEast , Neighbor.DownWest , |
|
Neighbor.DownSouth, Neighbor.DownNorth }); |
|
|
|
public static readonly ImmutableHashSet<Neighbor> All |
|
= AllAxisPlanes.Union(new[] { |
|
Neighbor.UpSouthEast, Neighbor.UpSouthWest, |
|
Neighbor.UpNorthEast, Neighbor.UpNorthWest, |
|
Neighbor.DownSouthEast, Neighbor.DownSouthWest, |
|
Neighbor.DownNorthEast, Neighbor.DownNorthWest }); |
|
} |
|
|
|
public static class NeighborExtensions |
|
{ |
|
const int SetBitX = 0b000010, ValueBitX = 0b000001; |
|
const int SetBitY = 0b001000, ValueBitY = 0b000100; |
|
const int SetBitZ = 0b100000, ValueBitZ = 0b010000; |
|
public static void Deconstruct(this Neighbor self, out int x, out int y, out int z) |
|
{ |
|
x = (((int)self & SetBitX) != 0) ? ((((int)self & ValueBitX) != 0) ? 1 : -1) : 0; |
|
y = (((int)self & SetBitY) != 0) ? ((((int)self & ValueBitY) != 0) ? 1 : -1) : 0; |
|
z = (((int)self & SetBitZ) != 0) ? ((((int)self & ValueBitZ) != 0) ? 1 : -1) : 0; |
|
} |
|
|
|
|
|
// public static Neighbor ToNeighbor(this Axis self, int v) |
|
// { |
|
// if ((v < -1) || (v > 1)) throw new ArgumentOutOfRangeException( |
|
// nameof(v), v, $"{nameof(v)} (={v}) must be within (-1, 1)"); |
|
// return self switch { |
|
// Axis.X => (v > 0) ? Neighbor.East : Neighbor.West , |
|
// Axis.Y => (v > 0) ? Neighbor.Up : Neighbor.Down , |
|
// Axis.Z => (v > 0) ? Neighbor.South : Neighbor.North, |
|
// _ => Neighbor.None |
|
// }; |
|
// } |
|
|
|
// public static Axis GetAxis(this Neighbor self) |
|
// => self switch { |
|
// Neighbor.East => Axis.X, |
|
// Neighbor.West => Axis.X, |
|
// Neighbor.Up => Axis.Y, |
|
// Neighbor.Down => Axis.Y, |
|
// Neighbor.South => Axis.Z, |
|
// Neighbor.North => Axis.Z, |
|
// _ => throw new ArgumentException(nameof(self), $"{self} is not one of FACINGS") |
|
// }; |
|
|
|
|
|
public static Neighbor ToNeighbor(this BlockFacing self) |
|
=> self switch { |
|
BlockFacing.East => Neighbor.East , |
|
BlockFacing.West => Neighbor.West , |
|
BlockFacing.Up => Neighbor.Up , |
|
BlockFacing.Down => Neighbor.Down , |
|
BlockFacing.South => Neighbor.South, |
|
BlockFacing.North => Neighbor.North, |
|
_ => throw new ArgumentException( |
|
$"'{self}' is not a valid BlockFacing", nameof(self)) |
|
}; |
|
|
|
public static BlockFacing ToBlockFacing(this Neighbor self) |
|
=> self switch { |
|
Neighbor.East => BlockFacing.East , |
|
Neighbor.West => BlockFacing.West , |
|
Neighbor.Up => BlockFacing.Up , |
|
Neighbor.Down => BlockFacing.Down , |
|
Neighbor.South => BlockFacing.South, |
|
Neighbor.North => BlockFacing.North, |
|
_ => throw new ArgumentException( |
|
$"'{self}' can't be converted to a valid BlockFacing", nameof(self)) |
|
}; |
|
|
|
|
|
public static Neighbor ToNeighbor(this (int x, int y, int z) p) |
|
{ |
|
var neighbor = Neighbor.None; |
|
if (p.x != 0) { |
|
if (p.x == 1) neighbor |= Neighbor.East; |
|
else if (p.x == -1) neighbor |= Neighbor.West; |
|
else throw new ArgumentOutOfRangeException( |
|
nameof(p), p.x, $"{nameof(p)}.x (={p.x}) must be within (-1, 1)"); |
|
} |
|
if (p.y != 0) { |
|
if (p.y == 1) neighbor |= Neighbor.Up; |
|
else if (p.y == -1) neighbor |= Neighbor.Down; |
|
else throw new ArgumentOutOfRangeException( |
|
nameof(p), p.y, $"{nameof(p)}.y (={p.y}) must be within (-1, 1)"); |
|
} |
|
if (p.z != 0) { |
|
if (p.z == 1) neighbor |= Neighbor.South; |
|
else if (p.z == -1) neighbor |= Neighbor.North; |
|
else throw new ArgumentOutOfRangeException( |
|
nameof(p), p.z, $"{nameof(p)}.z (={p.z}) must be within (-1, 1)"); |
|
} |
|
return neighbor; |
|
} |
|
|
|
public static Neighbor GetOpposite(this Neighbor self) |
|
{ var (x, y, z) = self; return (-x, -y, -z).ToNeighbor(); } |
|
|
|
|
|
public static BlockPos ToProperPos(this Neighbor self) |
|
{ var (x, y, z) = self; return new(x, y, z); } |
|
|
|
public static Vector3D<float> ToVector3(this Neighbor self) |
|
{ var (x, y, z) = self; return new(x, y, z); } |
|
|
|
|
|
public static bool IsNone(this Neighbor self) |
|
=> (self == Neighbor.None); |
|
|
|
public static bool IsHorizontal(this Neighbor self) |
|
=> Neighbors.Horizontals.Contains(self); |
|
public static bool IsVertical(this Neighbor self) |
|
=> Neighbors.Verticals.Contains(self); |
|
public static bool IsCardinal(this Neighbor self) |
|
=> Neighbors.Cardinals.Contains(self); |
|
public static bool IsFacing(this Neighbor self) |
|
=> Neighbors.Facings.Contains(self); |
|
public static bool IsValid(this Neighbor self) |
|
=> Neighbors.All.Contains(self); |
|
|
|
|
|
public static string ToShortString(this Neighbor self) |
|
{ |
|
if (!self.IsValid()) return "-"; |
|
var sb = new StringBuilder(3); |
|
foreach (var chr in self.ToString()) |
|
if ((chr >= 'A') && (chr <= 'Z')) // ASCII IsUpper |
|
sb.Append(chr + 0x20); // ASCII ToLower |
|
return sb.ToString(); |
|
} |
|
}
|
|
|