#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 nkast.Aether.Content.Pipeline { [ContentImporter(".vox", DisplayName = "Voxel Model Importer - Aether", DefaultProcessor = "ModelProcessor")] public class VoxelModelImporter : ContentImporter { 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; } /// /// Import a VOX file as Model /// private NodeContent VoxelProcess(VoxelContent voxel, ContentImporterContext context) { XYZI[] voxels = voxel.Voxels; uint[] palette = voxel.Palette; Vector3 scale = voxel.RealSize / voxel.GridSize; Vector3 centerOffset = new Vector3(1f, 1f, 1f) * (voxel.RealSize / -2f); Point3 corner000 = new Point3(0, 0, 0); Point3 corner100 = new Point3(1, 0, 0); Point3 corner010 = new Point3(0, 1, 0); Point3 corner110 = new Point3(1, 1, 0); Point3 corner001 = new Point3(0, 0, 1); Point3 corner101 = new Point3(1, 0, 1); Point3 corner011 = new Point3(0, 1, 1); Point3 corner111 = new Point3(1, 1, 1); Vector3 Forward = Vector3.Forward; Vector3 Backward = Vector3.Backward; Vector3 Left = Vector3.Left; Vector3 Right = Vector3.Right; Vector3 Up = Vector3.Up; Vector3 Down = Vector3.Down; for (int i = 0; i < voxels.Length; i++) { Point3 pt000 = voxels[i].Point.Add(ref corner000); Point3 pt100 = voxels[i].Point.Add(ref corner100); Point3 pt010 = voxels[i].Point.Add(ref corner010); Point3 pt110 = voxels[i].Point.Add(ref corner110); Point3 pt001 = voxels[i].Point.Add(ref corner001); Point3 pt101 = voxels[i].Point.Add(ref corner101); Point3 pt011 = voxels[i].Point.Add(ref corner011); Point3 pt111 = voxels[i].Point.Add(ref corner111); // back Vector3 p0 = pt000.ToVector3(); Vector3 p1 = pt100.ToVector3(); Vector3 p2 = pt010.ToVector3(); Vector3 p3 = pt110.ToVector3(); // front Vector3 p4 = pt001.ToVector3(); Vector3 p5 = pt101.ToVector3(); Vector3 p6 = pt011.ToVector3(); Vector3 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); } GeometryContent 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 normals = new List(); List colors = new List(); 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(VertexChannelNames.Normal(0), normals); geom.Vertices.Channels.Add(VertexChannelNames.Color(0), colors); return mesh; } List vertices = new List(); List indices = new List(); Dictionary vertexMap = new Dictionary(); 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; } } }