diff --git a/CHANGELOG.md b/CHANGELOG.md
index 514294f..684e6a2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-->
+## [3.1.0] - 2023-01-03
+
+### Added
+
+- Added `GlobalPosition` property to `Voxel`
+
## [3.0.0] - 2023-01-03
### Added
diff --git a/VoxReader.UnitTests/UnitTests.cs b/VoxReader.UnitTests/UnitTests.cs
index 527e749..8e00653 100644
--- a/VoxReader.UnitTests/UnitTests.cs
+++ b/VoxReader.UnitTests/UnitTests.cs
@@ -16,12 +16,30 @@ public class UnitTests
private const string TestFile_3x3x3_at_center_with_corner = "data/3x3x3_at_center_with_corner.zip";
private const string TestFile_groups = "data/groups.zip";
+ [Fact]
+ public void VoxReader_Read_GlobalVoxelPositionIsCorrect()
+ {
+ string file = Zip.UnzipFilesFromSevenZipArchive(TestFile_groups).First();
+
+ IVoxFile voxFile = VoxReader.Read(file);
+
+ voxFile.Models.Single(m => m.Name == "obj1").Voxels[0].GlobalPosition.Should().Be(new Vector3(0, 0, 0));
+ voxFile.Models.Single(m => m.Name == "obj2").Voxels[0].GlobalPosition.Should().Be(new Vector3(0, 0, 2));
+
+ voxFile.Models.Single(m => m.Name == "obj3").Voxels.Single(v => v.Color == Color.Blue).GlobalPosition.Should().Be(new Vector3(-3, 0, 3));
+ voxFile.Models.Single(m => m.Name == "obj3").Voxels.Single(v => v.Color == Color.Red).GlobalPosition.Should().Be(new Vector3(-1, 2, 5));
+
+ voxFile.Models.Single(m => m.Name == "obj4").Voxels.Single(v => v.Color == Color.Blue).GlobalPosition.Should().Be(new Vector3(-3, 0, 7));
+ voxFile.Models.Single(m => m.Name == "obj4").Voxels.Single(v => v.Color == Color.Red).GlobalPosition.Should().Be(new Vector3(-1, 2, 9));
+ }
+
[Fact]
public void VoxReader_Read_ModelNamesAreParsedCorrectly()
{
string file = Zip.UnzipFilesFromSevenZipArchive(TestFile_groups).First();
IVoxFile voxFile = VoxReader.Read(file);
+
voxFile.Models.Should().ContainSingle(m => m.Name == "obj1");
voxFile.Models.Should().ContainSingle(m => m.Name == "obj2");
voxFile.Models.Should().ContainSingle(m => m.Name == "obj3");
@@ -35,6 +53,7 @@ public void VoxReader_Read_ModelPositionsAreCorrectInGroups()
string file = Zip.UnzipFilesFromSevenZipArchive(TestFile_groups).First();
IVoxFile voxFile = VoxReader.Read(file);
+
voxFile.Models.Single(m => m.Name == "obj1").Position.Should().Be(new Vector3(0, 0, 0));
voxFile.Models.Single(m => m.Name == "obj2").Position.Should().Be(new Vector3(0, 0, 2));
voxFile.Models.Single(m => m.Name == "obj3").Position.Should().Be(new Vector3(-2, 1, 4));
@@ -48,6 +67,7 @@ public void VoxReader_Read_ModelPositionsAreCorrect()
string file = Zip.UnzipFilesFromSevenZipArchive(TestFile_MultipleModels).First();
IVoxFile voxFile = VoxReader.Read(file);
+
voxFile.Models.Single(m => m.Name == "black").Position.Should().Be(new Vector3(0, 0, 0));
voxFile.Models.Single(m => m.Name == "red").Position.Should().Be(new Vector3(2, 0, 0));
voxFile.Models.Single(m => m.Name == "green").Position.Should().Be(new Vector3(0, 2, 0));
@@ -63,6 +83,7 @@ public void VoxReader_Read_ModelPositionIsCorrectFor3x3x3Model()
string file = Zip.UnzipFilesFromSevenZipArchive(TestFile_3x3x3_at_center_with_corner).First();
IVoxFile voxFile = VoxReader.Read(file);
+
voxFile.Models.Single(m => m.Name == "obj1").Position.Should().Be(new Vector3(1, 1, 1));
}
diff --git a/VoxReader.UnitTests/VoxReader.UnitTests.csproj b/VoxReader.UnitTests/VoxReader.UnitTests.csproj
index bf4c5d3..d1420c8 100644
--- a/VoxReader.UnitTests/VoxReader.UnitTests.csproj
+++ b/VoxReader.UnitTests/VoxReader.UnitTests.csproj
@@ -7,10 +7,10 @@
-
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
@@ -22,11 +22,11 @@
-
+
-
+
diff --git a/VoxReader.UnitTests/data/groups.zip b/VoxReader.UnitTests/data/groups.zip
index 5488f97..3ab2b72 100644
--- a/VoxReader.UnitTests/data/groups.zip
+++ b/VoxReader.UnitTests/data/groups.zip
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8ca59bcad5d9f276a76770b2e0e504067584e2a8ef36243cff5b2d5af6fa823a
-size 2009
+oid sha256:4d7b132c3ac61b208995ecaa8f0b95dafb220222e27fb9469e41d9d112b0faaf
+size 2024
diff --git a/VoxReader/Color.cs b/VoxReader/Color.cs
index d883b15..a291dba 100644
--- a/VoxReader/Color.cs
+++ b/VoxReader/Color.cs
@@ -71,5 +71,11 @@ public override string ToString()
{
return $"R: {R} G: {G} B: {B} A: {A}";
}
+
+ internal static readonly Color Red = new(255, 0, 0, 255);
+ internal static readonly Color Green = new(0, 255, 0, 255);
+ internal static readonly Color Blue = new(0, 0, 255, 255);
+ internal static readonly Color White = new(255, 255, 255, 255);
+ internal static readonly Color Black = new(0, 0, 0, 255);
}
}
\ No newline at end of file
diff --git a/VoxReader/Helper.cs b/VoxReader/Helper.cs
index 9e5a7cc..7a54832 100644
--- a/VoxReader/Helper.cs
+++ b/VoxReader/Helper.cs
@@ -64,9 +64,10 @@ public static IEnumerable ExtractModels(IChunk mainChunk, IPalette palet
foreach (int id in ids)
{
string name = transformNodeChunk.Name;
- Vector3 position = GetGlobalTranslation(transformNodeChunk);
Vector3 size = sizeChunks[id].Size;
- var voxels = voxelChunks[id].Voxels.Select(voxel => new Voxel(voxel.Position, palette.Colors[voxel.ColorIndex - 1])).ToArray();
+ Vector3 position = GetGlobalTranslation(transformNodeChunk);
+
+ var voxels = voxelChunks[id].Voxels.Select(voxel => new Voxel(voxel.Position, position + voxel.Position - size / 2, palette.Colors[voxel.ColorIndex - 1])).ToArray();
// Create new model
var model = new Model(id, name, position, size, voxels, !processedModelIds.Add(id));
@@ -77,11 +78,11 @@ public static IEnumerable ExtractModels(IChunk mainChunk, IPalette palet
Vector3 GetGlobalTranslation(ITransformNodeChunk target)
{
Vector3 position = target.Frames[0].Translation;
-
+
while (TryGetParentTransformNodeChunk(target, out ITransformNodeChunk parent))
{
position += parent.Frames[0].Translation;
-
+
target = parent;
}
diff --git a/VoxReader/Vector3.cs b/VoxReader/Vector3.cs
index ecb5925..3a565b6 100644
--- a/VoxReader/Vector3.cs
+++ b/VoxReader/Vector3.cs
@@ -8,12 +8,12 @@ public struct Vector3 : IEquatable
/// The x-component of the vector (right).
///
public readonly int X;
-
+
///
/// The y-component of the vector (forward).
///
public readonly int Y;
-
+
///
/// The z-component of the vector (up).
///
@@ -51,7 +51,9 @@ public override int GetHashCode()
return hashCode;
}
}
-
+
+ //TODO: add unit tests
+
public static bool operator ==(Vector3 a, Vector3 b)
{
return a.Equals(b);
@@ -61,10 +63,25 @@ public override int GetHashCode()
{
return !(a == b);
}
-
+
public static Vector3 operator +(Vector3 a, Vector3 b)
{
return new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
}
+
+ public static Vector3 operator -(Vector3 a, Vector3 b)
+ {
+ return new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
+ }
+
+ public static Vector3 operator *(Vector3 a, int i)
+ {
+ return new Vector3(a.X * i, a.Y * i, a.Z * i);
+ }
+
+ public static Vector3 operator /(Vector3 a, int i)
+ {
+ return new Vector3(a.X / i, a.Y / i, a.Z / i);
+ }
}
}
\ No newline at end of file
diff --git a/VoxReader/Voxel.cs b/VoxReader/Voxel.cs
index 5c5c320..21d56a4 100644
--- a/VoxReader/Voxel.cs
+++ b/VoxReader/Voxel.cs
@@ -3,18 +3,24 @@ namespace VoxReader
public readonly struct Voxel
{
///
- /// The position of the voxel.
+ /// The position of the voxel in the model.
///
public Vector3 Position { get; }
+
+ ///
+ /// The global position of the voxel in the scene.
+ ///
+ public Vector3 GlobalPosition { get; }
///
/// The color of the voxel.
///
public Color Color { get; }
- internal Voxel(Vector3 position, Color color)
+ internal Voxel(Vector3 position, Vector3 globalPosition, Color color)
{
Position = position;
+ GlobalPosition = globalPosition;
Color = color;
}
diff --git a/VoxReader/package.json b/VoxReader/package.json
index 61f159d..37b6e8e 100644
--- a/VoxReader/package.json
+++ b/VoxReader/package.json
@@ -1,6 +1,6 @@
{
"name": "com.sandrofigo.voxreader",
- "version": "3.0.0",
+ "version": "3.1.0",
"displayName": "VoxReader",
"description": "A C# library to read .vox files created with MagicaVoxel",
"documentationUrl": "https://github.com/sandrofigo/VoxReader",