Browse Source

Merge pull request #12 from tainicom/VoxelModelImporter

VoxelModel Importer
Nikos Kastellanos 5 years ago
parent
commit
36170132f6

+ 7 - 0
Aether.Extras.WINDOWS.MG.sln

@@ -31,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aether.Shaders.InfiniteGrid
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SLMCImporter.WINDOWS.MG", "Content.Pipeline\SLMCImporter\SLMCImporter.WINDOWS.MG.csproj", "{C9FA924B-DA91-4641-8B7D-CBC09E5560AE}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VoxelImporters.WINDOWS.MG", "Content.Pipeline\VoxelImporters\VoxelImporters.WINDOWS.MG.csproj", "{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -85,6 +87,10 @@ Global
 		{C9FA924B-DA91-4641-8B7D-CBC09E5560AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C9FA924B-DA91-4641-8B7D-CBC09E5560AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C9FA924B-DA91-4641-8B7D-CBC09E5560AE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -99,5 +105,6 @@ Global
 		{E710FBEA-8C75-405D-B6B4-CFC82CB48FB5} = {A921886B-C6F7-4FF8-8668-EC20004C464A}
 		{08296A2E-BECF-4DB9-A518-8A613D07B80E} = {13D47E11-4A7C-49C8-942E-2543E9C0098A}
 		{C9FA924B-DA91-4641-8B7D-CBC09E5560AE} = {A921886B-C6F7-4FF8-8668-EC20004C464A}
+		{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9} = {A921886B-C6F7-4FF8-8668-EC20004C464A}
 	EndGlobalSection
 EndGlobal

+ 7 - 0
Aether.Extras.WINDOWS.XNA.sln

@@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aether.Shaders.InfiniteGrid
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SLMCImporter.WINDOWS.XNA", "Content.Pipeline\SLMCImporter\SLMCImporter.WINDOWS.XNA.csproj", "{497B1130-EB63-4057-BC40-F60D6FFA50CA}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VoxelImporters.WINDOWS.XNA", "Content.Pipeline\VoxelImporters\VoxelImporters.WINDOWS.XNA.csproj", "{0690782F-0000-0000-0000-000000000000}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x86 = Debug|x86
@@ -71,6 +73,10 @@ Global
 		{497B1130-EB63-4057-BC40-F60D6FFA50CA}.Debug|x86.Build.0 = Debug|x86
 		{497B1130-EB63-4057-BC40-F60D6FFA50CA}.Release|x86.ActiveCfg = Release|x86
 		{497B1130-EB63-4057-BC40-F60D6FFA50CA}.Release|x86.Build.0 = Release|x86
+		{0690782F-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+		{0690782F-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
+		{0690782F-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+		{0690782F-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -80,6 +86,7 @@ Global
 		{E22F02E7-6799-4C14-B9B3-B461D6E9AB6E} = {F6B6E505-6037-49E4-9060-8B29A7B99BC1}
 		{90E6017D-198B-4470-BF9B-8B8791C295CC} = {F6B6E505-6037-49E4-9060-8B29A7B99BC1}
 		{497B1130-EB63-4057-BC40-F60D6FFA50CA} = {F6B6E505-6037-49E4-9060-8B29A7B99BC1}
+		{0690782F-0000-0000-0000-000000000000} = {F6B6E505-6037-49E4-9060-8B29A7B99BC1}
 		{89E0198E-7298-411A-B5C1-61F2754A3F80} = {EFC7A27C-C20B-4BE7-8B3A-2B109991D704}
 		{B82B862D-C728-4A10-8A56-65D688E022C8} = {EFC7A27C-C20B-4BE7-8B3A-2B109991D704}
 		{908EC8FF-B0ED-478A-B486-702E578AF64A} = {EFC7A27C-C20B-4BE7-8B3A-2B109991D704}

+ 36 - 0
Content.Pipeline/VoxelImporters/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Aether.Content.Pipeline.VoxelImporters")]
+[assembly: AssemblyProduct("VoxelImporters")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyCopyright("Copyright © Kastellanos Nikolaos  2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("C690782F-D4A6-4608-A05F-A0E0C4F28089")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 83 - 0
Content.Pipeline/VoxelImporters/VertexPositionNormalColor.cs

@@ -0,0 +1,83 @@
+#region License 
+//   Copyright 2020 Kastellanos Nikolaos
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+#endregion
+
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace tainicom.Aether.Content.Pipeline
+{
+    public struct VertexPositionNormalColor : IVertexType, IEquatable<VertexPositionNormalColor>
+    {
+        public Vector3 Position;
+        public Vector3 Normal;
+        public Color Color;
+
+        #region IVertexType Members
+        public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration(
+                new VertexElement[] 
+                {
+                    new VertexElement( 0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
+                    new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
+                    new VertexElement(24, VertexElementFormat.Color, VertexElementUsage.Color, 0)
+                });
+
+        VertexDeclaration IVertexType.VertexDeclaration
+        {
+            get { return VertexDeclaration; }
+        }
+        #endregion
+
+        public VertexPositionNormalColor(Vector3 position, Vector3 normal, Color color)
+        {
+            this.Position = position;
+            this.Normal = normal;
+            this.Color = color;
+        }
+
+        public override int GetHashCode()
+        {
+            return (Position.X.GetHashCode() ^ Position.Y.GetHashCode() ^ Position.Z.GetHashCode()
+                  ^ Normal.X.GetHashCode() ^ Normal.Y.GetHashCode() ^ Normal.Z.GetHashCode()
+                  ^ Color.GetHashCode()
+                 );
+        }
+        
+        public override bool Equals(object obj)
+        {
+            if (obj is VertexPositionNormalColor)
+                return Equals((VertexPositionNormalColor)obj);
+            else
+                return false;
+        }
+
+        public bool Equals(VertexPositionNormalColor other)
+        {
+            return (Position.X.Equals(other.Position.X) && Position.Y.Equals(other.Position.Y) && Position.Z.Equals(other.Position.Z)
+                  && Normal.X.Equals(other.Normal.X) && Normal.Y.Equals(other.Normal.Y) && Normal.Z.Equals(other.Normal.Z)
+                  && Color.PackedValue.Equals(other.Color.PackedValue)
+                 );
+        }
+
+        bool IEquatable<VertexPositionNormalColor>.Equals(VertexPositionNormalColor other)
+        {
+            return (Position.X.Equals(other.Position.X) && Position.Y.Equals(other.Position.Y) && Position.Z.Equals(other.Position.Z)
+                  && Normal.X.Equals(other.Normal.X) && Normal.Y.Equals(other.Normal.Y) && Normal.Z.Equals(other.Normal.Z)
+                  && Color.PackedValue.Equals(other.Color.PackedValue)
+                 );
+        }
+    }
+}

+ 70 - 0
Content.Pipeline/VoxelImporters/Vox/VoxHeader.cs

@@ -0,0 +1,70 @@
+#region License
+//   Copyright 2020 Kastellanos Nikolaos
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+#endregion
+
+using System;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace tainicom.Aether.Content.Pipeline
+{
+    struct VoxHeader
+    {
+        static readonly int VoxSignature = (BitConverter.IsLittleEndian) ? 0x20584F56 : 0x564F5820;
+
+        public readonly Int32 Signature;
+        public readonly Int32 Version;
+
+        public VoxHeader(System.IO.BinaryReader reader)
+        {
+            Signature = reader.ReadInt32();
+            if (Signature != VoxHeader.VoxSignature)
+                throw new InvalidContentException("This does not appear to be a VOX file");
+            Version = reader.ReadInt32();
+            if (Version != 150)
+                throw new InvalidContentException("Unknown version");
+        }
+    }
+
+    struct Chunk
+    {
+        public readonly int ChunkId;
+        public readonly int NumBytesOfChunkContent;
+        public readonly int NumBytesOfChildrenChunks;
+
+        public Chunk(System.IO.BinaryReader reader)
+        {
+            ChunkId = reader.ReadInt32();
+            NumBytesOfChunkContent = reader.ReadInt32();
+            NumBytesOfChildrenChunks = reader.ReadInt32();
+        }
+
+        public const int MAIN = 0x4E49414D;
+        public const int PACK = 0x4B434150;
+        public const int SIZE = 0x455A4953;
+        public const int XYZI = 0x495A5958;
+        public const int RGBA = 0x41424752;
+        public const int MATT = 0x5454414D;
+    }
+
+    struct XYZI
+    {
+        public Point3 Point;
+        public byte ColorIndex;
+        public Sides SharedSides;
+    }
+
+}
+
+

+ 131 - 0
Content.Pipeline/VoxelImporters/Vox/VoxImporter.cs

@@ -0,0 +1,131 @@
+#region License
+//   Copyright 2020 Kastellanos Nikolaos
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+#endregion
+
+using System;
+using System.IO;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content.Pipeline;
+
+namespace tainicom.Aether.Content.Pipeline
+{
+    class VoxImporter
+    {
+        internal VoxelContent ImportVox(string filename, ContentImporterContext context)
+        {
+            VoxelContent output;
+            using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
+            {
+                using (var reader = new BinaryReader(stream))
+                {
+                    var contentIdentity = new ContentIdentity(filename);
+                    output = ImportVox(reader, contentIdentity, context);
+                }
+            }
+
+            return output;
+        }
+
+        private VoxelContent ImportVox(BinaryReader reader, ContentIdentity contentIdentity, ContentImporterContext context)
+        {
+            VoxelContent output = null;
+
+            var header = new VoxHeader(reader);
+
+            var main = new Chunk(reader);
+            if (main.ChunkId != Chunk.MAIN)
+                throw new InvalidContentException("MAIN was expected");
+
+            var chunk = new Chunk(reader);
+            if (chunk.ChunkId == Chunk.PACK)
+                throw new InvalidContentException("PACK is not supported");
+
+            var chunkSIZE = chunk;
+            if (chunkSIZE.ChunkId != Chunk.SIZE)
+                throw new InvalidContentException("SIZE was expected");
+            int sizeX = reader.ReadInt32();
+            int sizeZ = reader.ReadInt32();
+            int sizeY = reader.ReadInt32();
+
+
+            var chunkXYZI = new Chunk(reader);
+            if (chunkXYZI.ChunkId != Chunk.XYZI)
+                throw new InvalidContentException("XYZI was expected");
+            var numVoxels = reader.ReadInt32();
+
+            XYZI[] voxels = new XYZI[numVoxels];
+            for (var i = 0; i < numVoxels; i++)
+            {
+                var x = reader.ReadByte();
+                var z = reader.ReadByte();
+                var y = reader.ReadByte();
+                var ColorIndex = reader.ReadByte();
+                z = (byte)(sizeZ - 1 - z);
+
+                voxels[i].Point = new Point3(x, y, z);
+                voxels[i].ColorIndex = ColorIndex;
+            }
+
+            uint[] palette = default_palette;
+            if (reader.BaseStream.Position < reader.BaseStream.Length)
+            {
+                chunk = new Chunk(reader);
+
+                if (chunk.ChunkId == Chunk.RGBA)
+                {
+                    palette = new UInt32[256];
+
+                    // color [0-254] are mapped to palette index [1-255]
+                    for (int i = 1; i < 256; i++)
+                    {
+                        palette[i] = reader.ReadUInt32();
+                    }
+                    // the last color is not mapped
+                    reader.ReadUInt32();
+
+                }
+            }
+
+            output = new VoxelContent()
+            {
+                GridSize = new Vector3(sizeX, sizeY, sizeZ),
+                Voxels = voxels,
+                Palette = palette,
+            };
+
+            return output;
+        }
+        
+        readonly uint[] default_palette = new uint[]
+        {
+            0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff,
+            0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff,
+            0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc,
+            0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc,
+            0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99,
+            0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699,
+            0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66,
+            0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666,
+            0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066,
+            0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933,
+            0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033,
+            0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00,
+            0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300,
+            0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044,
+            0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000,
+            0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111
+        };
+    }
+}

+ 151 - 0
Content.Pipeline/VoxelImporters/VoxelContent.cs

@@ -0,0 +1,151 @@
+#region License
+//   Copyright 2020 Kastellanos Nikolaos
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Xna.Framework;
+
+namespace tainicom.Aether.Content.Pipeline
+{
+    public class VoxelContent
+    {
+        internal Vector3 GridSize = Vector3.Zero;
+        internal Vector3 RealSize = Vector3.One;
+
+        internal XYZI[] Voxels;
+        internal uint[] Palette;
+
+        internal void MarkSharedSides()
+        {
+            HashSet<Point3> blocks = new HashSet<Point3>(Voxels.Select<XYZI, Point3>((v) => { return v.Point; }));
+
+            //for(int i = 0; i< Voxels.Length;i++)
+            System.Threading.Tasks.Parallel.For(0, Voxels.Length, (i) =>
+            {
+                var vpt = Voxels[i].Point;
+
+                if (blocks.Contains(new Point3(vpt.X - 1, vpt.Y, vpt.Z)))
+                    Voxels[i].SharedSides |= Sides.Left;
+                if (blocks.Contains(new Point3(vpt.X + 1, vpt.Y, vpt.Z)))
+                    Voxels[i].SharedSides |= Sides.Right;
+
+                if (blocks.Contains(new Point3(vpt.X, vpt.Y - 1, vpt.Z)))
+                    Voxels[i].SharedSides |= Sides.Down;
+                if (blocks.Contains(new Point3(vpt.X, vpt.Y + 1, vpt.Z)))
+                    Voxels[i].SharedSides |= Sides.Up;
+
+                if (blocks.Contains(new Point3(vpt.X, vpt.Y, vpt.Z + 1)))
+                    Voxels[i].SharedSides |= Sides.Backward;
+                if (blocks.Contains(new Point3(vpt.X, vpt.Y, vpt.Z - 1)))
+                    Voxels[i].SharedSides |= Sides.Forward;
+            //}
+            });
+
+            return;
+        }
+
+        internal void RemoveHiddenBlocks()
+        {
+            var visibleBlocks2 = Voxels.Where((v) => { return v.SharedSides != Sides.All; });
+            Voxels = visibleBlocks2.ToArray();
+
+            //HashSet<Point3> blocks = new HashSet<Point3>( Voxels.Select<XYZI, Point3>((v) => { return v.Point; }) );
+            //HashSet<Point3> insideBlocks = new HashSet<Point3>();
+            
+            //for (int z = 1; z < GridSize.Z - 1; z++)
+            //{
+            //    for (int y = 1; y < GridSize.Y - 1; y++)
+            //    {
+            //        for (int x = 0; x < GridSize.X - 1; x++)
+            //        {
+            //            if (blocks.Contains(new Point3(x-1, y, z)) &&
+            //                blocks.Contains(new Point3(x+1, y, z)) &&
+            //                blocks.Contains(new Point3(x, y-1, z)) &&
+            //                blocks.Contains(new Point3(x, y+1, z)) &&
+            //                blocks.Contains(new Point3(x, y, z-1)) &&
+            //                blocks.Contains(new Point3(x, y, z+1))
+            //               )
+            //            {
+            //                insideBlocks.Add(new Point3(x, y, z));
+            //            }
+            //        }
+            //    }
+            //}
+
+            //var visibleBlocks = Voxels.Where((v) => { return !insideBlocks.Contains(v.Point); });
+            //Voxels = visibleBlocks.ToArray();
+
+            return;
+        }
+    }
+
+    internal struct Point3
+    {
+        public readonly short X, Y, Z;
+
+        public Point3(byte x, byte y, byte z)
+        {
+            X = x;
+            Y = y;
+            Z = z;
+        }
+
+        public Point3(int x, int y, int z)
+        {
+            X = (byte)x;
+            Y = (byte)y;
+            Z = (byte)z;
+        }
+
+        public override int GetHashCode()
+        {
+            return ((X) ^ (Y*256) ^ (Z*(256*256)));
+        }
+
+        internal Point3 Add(ref Point3 right)
+        {
+            return new Point3(
+                (short)(X + right.X),
+                (short)(Y + right.Y),
+                (short)(Z + right.Z)
+                );
+        }
+
+        internal Vector3 ToVector3()
+        {
+            Vector3 result;
+            result.X = X;
+            result.Y = Y;
+            result.Z = Z;
+            return result;
+        }
+    }
+
+    internal enum Sides
+    {
+        None = 0,
+        Right = 1,
+        Left = 2,
+        Up = 4,
+        Down = 8,
+        Forward = 16,
+        Backward = 32,
+
+        All = 63
+    }
+}

+ 66 - 0
Content.Pipeline/VoxelImporters/VoxelImporters.WINDOWS.MG.csproj

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{AA15CF95-0AF2-4346-9465-CB6EDBE22ED9}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>tainicom.Aether.Content.Pipeline</RootNamespace>
+    <AssemblyName>Aether.Content.Pipeline.VoxelImporters</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\bin\Debug\Windows\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;WINDOWS MG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\bin\Release\Windows\</OutputPath>
+    <DefineConstants>TRACE;WINDOWS MG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Vox\VoxImporter.cs" />
+    <Compile Include="Vox\VoxHeader.cs" />
+    <Compile Include="VertexPositionNormalColor.cs" />
+    <Compile Include="VoxelContent.cs" />
+    <Compile Include="VoxelModelImporter.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.Portable" Version="3.2.99.1-Beta">
+      <PrivateAssets>all</PrivateAssets>
+      <ExcludeAssets>runtime</ExcludeAssets>
+    </PackageReference>
+    <PackageReference Include="MonoGame.Framework.Content.Pipeline.Portable" Version="3.2.99.1-Beta">
+      <PrivateAssets>all</PrivateAssets>
+      <ExcludeAssets>runtime</ExcludeAssets>
+    </PackageReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 64 - 0
Content.Pipeline/VoxelImporters/VoxelImporters.WINDOWS.XNA.csproj

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+  <PropertyGroup>
+    <ProjectGuid>{690782F-D4A6-4608-A05F-A0E0C4F28089}</ProjectGuid>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>tainicom.Aether.Content.Pipeline</RootNamespace>
+    <AssemblyName>Aether.Content.Pipeline.VoxelImporters</AssemblyName>
+    <XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
+    <XnaPlatform>Windows</XnaPlatform>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\bin\Debug\Windows.XNA\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;WINDOWS XNA</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\bin\Release\Windows.XNA\</OutputPath>
+    <DefineConstants>TRACE;WINDOWS XNA</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
+    <Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" />
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.XML" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Vox\VoxImporter.cs" />
+    <Compile Include="Vox\VoxHeader.cs" />
+    <Compile Include="VertexPositionNormalColor.cs" />
+    <Compile Include="VoxelContent.cs" />
+    <Compile Include="VoxelModelImporter.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+     Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 247 - 0
Content.Pipeline/VoxelImporters/VoxelModelImporter.cs

@@ -0,0 +1,247 @@
+#region License
+//   Copyright 2015-2016 Kastellanos Nikolaos
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace tainicom.Aether.Content.Pipeline
+{
+    [ContentImporter(".vox", DisplayName = "Voxel Model Importer - Aether", DefaultProcessor = "ModelProcessor")]
+    public class VoxelModelImporter : ContentImporter<NodeContent>
+    {
+        public override NodeContent Import(string filename, ContentImporterContext context)
+        {
+            VoxelContent voxel = null;
+
+            if (Path.GetExtension(filename) == ".vox")
+            {
+                VoxImporter voxelImporter = new VoxImporter();
+                voxel = voxelImporter.ImportVox(filename, context);
+            }
+            else
+            {
+                throw new InvalidContentException("File type not supported.");
+            }
+            
+            voxel.MarkSharedSides();
+
+            voxel.RemoveHiddenBlocks();
+            
+            NodeContent output = VoxelProcess(voxel, context);
+            
+            return output;
+        }
+
+        /// <summary>
+        /// Import a VOX file as Model
+        /// </summary>
+        private NodeContent VoxelProcess(VoxelContent voxel, ContentImporterContext context)
+        {
+            XYZI[] voxels = voxel.Voxels;
+            uint[] palette = voxel.Palette;
+
+            var scale = voxel.RealSize / voxel.GridSize;
+            Vector3 centerOffset = new Vector3(1f, 0f, 1f) * (voxel.RealSize / -2f);
+
+            var corner000 = new Point3(0, 0, 0);
+            var corner100 = new Point3(1, 0, 0);
+            var corner010 = new Point3(0, 1, 0);
+            var corner110 = new Point3(1, 1, 0);
+            var corner001 = new Point3(0, 0, 1);
+            var corner101 = new Point3(1, 0, 1);
+            var corner011 = new Point3(0, 1, 1);
+            var corner111 = new Point3(1, 1, 1);
+
+
+            var Forward = Vector3.Forward;
+            var Backward = Vector3.Backward;
+            var Left = Vector3.Left;
+            var Right = Vector3.Right;
+            var Up = Vector3.Up;
+            var Down = Vector3.Down;
+
+            for (int i = 0; i < voxels.Length; i++)
+            {
+                var pt000 = voxels[i].Point.Add(ref corner000);
+                var pt100 = voxels[i].Point.Add(ref corner100);
+                var pt010 = voxels[i].Point.Add(ref corner010);
+                var pt110 = voxels[i].Point.Add(ref corner110);
+                var pt001 = voxels[i].Point.Add(ref corner001);
+                var pt101 = voxels[i].Point.Add(ref corner101);
+                var pt011 = voxels[i].Point.Add(ref corner011);
+                var pt111 = voxels[i].Point.Add(ref corner111);
+
+                // back
+                var p0 = pt000.ToVector3();
+                var p1 = pt100.ToVector3();
+                var p2 = pt010.ToVector3();
+                var p3 = pt110.ToVector3();
+
+                // front
+                var p4 = pt001.ToVector3();
+                var p5 = pt101.ToVector3();
+                var p6 = pt011.ToVector3();
+                var p7 = pt111.ToVector3();
+
+                Vector3.Multiply(ref p0, ref scale, out p0); Vector3.Add(ref p0, ref centerOffset, out p0);
+                Vector3.Multiply(ref p1, ref scale, out p1); Vector3.Add(ref p1, ref centerOffset, out p1);
+                Vector3.Multiply(ref p2, ref scale, out p2); Vector3.Add(ref p2, ref centerOffset, out p2);
+                Vector3.Multiply(ref p3, ref scale, out p3); Vector3.Add(ref p3, ref centerOffset, out p3);
+                Vector3.Multiply(ref p4, ref scale, out p4); Vector3.Add(ref p4, ref centerOffset, out p4);
+                Vector3.Multiply(ref p5, ref scale, out p5); Vector3.Add(ref p5, ref centerOffset, out p5);
+                Vector3.Multiply(ref p6, ref scale, out p6); Vector3.Add(ref p6, ref centerOffset, out p6);
+                Vector3.Multiply(ref p7, ref scale, out p7); Vector3.Add(ref p7, ref centerOffset, out p7);
+
+                vertex.Color.PackedValue = palette[voxels[i].ColorIndex];
+
+                if ((voxels[i].SharedSides & Sides.Forward) == 0)
+                {
+                    vertex.Normal = Forward;
+                    AddVertex(ref p1);
+                    AddVertex(ref p3);
+                    AddVertex(ref p0);
+
+                    AddVertex(ref p0);
+                    AddVertex(ref p3);
+                    AddVertex(ref p2);
+                }
+                if ((voxels[i].SharedSides & Sides.Backward) == 0)
+                {
+                    vertex.Normal = Backward;
+                    AddVertex(ref p4);
+                    AddVertex(ref p6);
+                    AddVertex(ref p5);
+
+                    AddVertex(ref p5);
+                    AddVertex(ref p6);
+                    AddVertex(ref p7);
+                }
+
+                if ((voxels[i].SharedSides & Sides.Left) == 0)
+                {
+                    vertex.Normal = Left;
+                    AddVertex(ref p2);
+                    AddVertex(ref p6);
+                    AddVertex(ref p0);
+
+                    AddVertex(ref p0);
+                    AddVertex(ref p6);
+                    AddVertex(ref p4);
+                }
+                if ((voxels[i].SharedSides & Sides.Right) == 0)
+                {
+                    vertex.Normal = Right;
+                    AddVertex(ref p1);
+                    AddVertex(ref p5);
+                    AddVertex(ref p3);
+
+                    AddVertex(ref p3);
+                    AddVertex(ref p5);
+                    AddVertex(ref p7);
+                }
+
+                if ((voxels[i].SharedSides & Sides.Up) == 0)
+                {
+                    vertex.Normal = Up;
+                    AddVertex(ref p7);
+                    AddVertex(ref p6);
+                    AddVertex(ref p3);
+
+                    AddVertex(ref p3);
+                    AddVertex(ref p6);
+                    AddVertex(ref p2);
+                }
+                if ((voxels[i].SharedSides & Sides.Down) == 0)
+                {
+                    vertex.Normal = Down;
+                    AddVertex(ref p5);
+                    AddVertex(ref p1);
+                    AddVertex(ref p4);
+
+                    AddVertex(ref p4);
+                    AddVertex(ref p1);
+                    AddVertex(ref p0);
+                }
+            }
+
+            MeshContent mesh = new MeshContent();
+            mesh.Name = "voxel";
+
+            for (int pi = 0; pi < this.vertices.Count; pi++)
+            {
+                mesh.Positions.Add(this.vertices[pi].Position);
+            }
+
+            var geom = new GeometryContent();
+            mesh.Geometry.Add(geom);
+            BasicMaterialContent material = new BasicMaterialContent();
+            geom.Material = material;
+
+            for (int pi = 0; pi < this.vertices.Count; pi++)
+            {
+                geom.Vertices.Add(pi);
+            }
+
+            for (int ii = 0; ii < this.indices.Count; ii++)
+            {
+                geom.Indices.Add(this.indices[ii]);
+            }
+
+            List<Vector3> normals = new List<Vector3>();
+            List<Color> colors = new List<Color>();
+
+            for (int vi = 0; vi < this.vertices.Count; vi++)
+            {
+                var vertex = vertices[vi];
+                normals.Add(vertex.Normal);
+                colors.Add(vertex.Color);
+            }
+
+            geom.Vertices.Channels.Add<Vector3>(VertexChannelNames.Normal(0), normals);
+            geom.Vertices.Channels.Add<Color>(VertexChannelNames.Color(0), colors);
+
+            return mesh;
+        }
+
+        List<VertexPositionNormalColor> vertices = new List<VertexPositionNormalColor>();
+        List<int> indices = new List<int>();
+        Dictionary<VertexPositionNormalColor, int> vertexMap = new Dictionary<VertexPositionNormalColor, int>();
+        VertexPositionNormalColor vertex;
+
+        private int AddVertex(ref Vector3 position)
+        {
+            vertex.Position = position;
+
+            int vertIndx;
+            if (!vertexMap.TryGetValue(vertex, out vertIndx))
+            {
+                vertIndx = vertices.Count;
+                vertices.Add(vertex);
+                vertexMap.Add(vertex, vertIndx);
+            }
+
+            indices.Add(vertIndx);
+
+            return vertIndx;
+        }
+
+    }
+}

+ 1 - 0
README.md

@@ -12,6 +12,7 @@ MonoGame Content Importers, Shaders, etc
 * 'DynamicModel' - Base Processor to customize the build in Model. It allows to modify
 VertexBuffer & IndexBuffers, make them Dynamic and WriteOnly.
 * 'AtlasImporter' - Import sprite atlas. Supports .tmx files. Mipmaps are generated individually for each sprite, no color-leak.
+* 'VoxelModelImporter' - Import .vox files as 3D Models.
 
 ## tainicom.Aether.Animation
 

BIN
bin/Release/Windows.XNA/Aether.Content.Pipeline.VoxelImporters.dll


BIN
bin/Release/Windows/Aether.Content.Pipeline.VoxelImporters.dll