/// <summary> /// Building function as co-routine /// </summary> /// <param name="voxels">Storage instance including collected voxels</param> /// <param name="bounds">Bounding box in absolute space</param> /// <returns>Enumerator for co-routine processing</returns> protected virtual IEnumerator CoBuild(Storage voxels, Bounds bounds) { // Check for given array if (voxels != null) { // Create target file var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write); if (fileStream != null) { // Create steam writer instance var streamWriter = new StreamWriter(fileStream); if (streamWriter != null) { // Store file header streamWriter.WriteLine("ply"); streamWriter.WriteLine("format ascii 1.0"); if (assetAuthor != null && assetAuthor.Length > 0) { streamWriter.WriteLine("comment Author: " + assetAuthor); } streamWriter.WriteLine("obj_info Generated by Voxels for Unity"); streamWriter.WriteLine("element vertex " + voxels.Count.ToString()); streamWriter.WriteLine("property float x"); streamWriter.WriteLine("property float y"); streamWriter.WriteLine("property float z"); streamWriter.WriteLine("property float red"); streamWriter.WriteLine("property float green"); streamWriter.WriteLine("property float blue"); streamWriter.WriteLine("property float alpha"); streamWriter.WriteLine("end_header"); Voxels.Storage.Iterator iterator = voxels.GetIterator(); Material material; int x, y, z; int voxelIndex = 0; Vector3 factor = new Vector3(bounds.size.x / voxels.Width, bounds.size.y / voxels.Height, bounds.size.z / voxels.Depth); // Store material colors of all input voxels while ((material = iterator.GetNextMaterial(out x, out y, out z)) != null) { streamWriter.WriteLine((x * factor.x + bounds.min.x) + " " + (y * factor.y + bounds.min.y) + " " + (z * factor.z + bounds.min.z) + " " + material.color.r + " " + material.color.g + " " + material.color.b + " " + material.color.a); ++voxelIndex; } // Close file stream streamWriter.Close(); streamWriter = null; } // Close file stream fileStream.Close(); fileStream = null; } } // Finish function progress = 1; yield return(null); }
/// <summary> /// Building function as co-routine /// </summary> /// <param name="voxels">Storage instance including collected voxels</param> /// <param name="bounds">Bounding box in absolute space</param> /// <returns>Enumerator for co-routine processing</returns> protected virtual IEnumerator CoBuild(Storage voxels, Bounds bounds) { // Check for given array if (voxels != null) { // Create target file var fileStream = new BinaryWriter(File.Open(filePath, FileMode.OpenOrCreate)); if (fileStream != null) { // Resolution limit for file format int maximumWidth = 256; int maximumHeight = 256; int maximumSlice = 256; // Store file type identifier fileStream.Write(new char[] { 'V', 'O', 'X', ' ' }); fileStream.Write((int)150); // Begin main chunk fileStream.Write(new char[] { 'M', 'A', 'I', 'N' }); fileStream.Write((int)0); var sizePointer = fileStream.BaseStream.Position; fileStream.Write((int)(sizeof(char) * 4 + sizeof(int) * 3)); // Write resolution fileStream.Write(new char[] { 'S', 'I', 'Z', 'E' }); fileStream.Write((int)(sizeof(int) * 3)); fileStream.Write((int)0); fileStream.Write((int)voxels.Width < maximumWidth ? voxels.Width : maximumWidth); fileStream.Write((int)voxels.Height < maximumHeight ? voxels.Height : maximumHeight); fileStream.Write((int)voxels.Depth < maximumSlice ? voxels.Depth : maximumSlice); Material[] outputMaterials; Dictionary <int, int> assignments; var materialGroups = new Dictionary <Material, int>(); var materialsList = new List <Material>(); int materialsCount = 0; Voxels.Storage.Iterator iterator = voxels.GetIterator(); Material material; int x, y, z; int voxelsNumber = 0; int voxelsCount = 0; // Interrupt co-routine progress = 0; yield return(null); // Process materials of all input voxels while ((material = iterator.GetNextMaterial(out x, out y, out z)) != null) { // Convert coordinates to format space var column = voxels.Width - x - 1; var line = voxels.Depth - z - 1; var slice = y; // Check if coordinate is supported by file format if (column < maximumWidth && line < maximumHeight && slice < maximumSlice) { // Add material to list and hash table if it is new if (!materialGroups.ContainsKey(material)) { materialGroups.Add(material, materialsList.Count); materialsList.Add(material); ++materialsCount; } // Increase number of voxels to store to file ++voxelsCount; } // Compute current progression if (++voxelsNumber % 1000 == 0) { progress = (float)voxelsNumber / (float)voxels.Count * 0.25f; yield return(null); } } // Interrupt co-routine progress = 0.25f; yield return(null); // Minimize number of colors to given limit var materialReducer = new MaterialReducer(this, materialsList, 254); if (materialReducer != null) { // Wait until reduction has been finished float progress; while ((progress = materialReducer.GetProgress()) < 1) { this.progress = progress * 0.5f + 0.25f; yield return(null); } // Get reduced materials and assignment pointers from original ones materialReducer.GetResult(out outputMaterials, out assignments); } else { outputMaterials = null; assignments = null; } // Interrupt co-routine progress = 0.75f; yield return(null); // Store voxels with assigned color index to file fileStream.Write(new char[] { 'X', 'Y', 'Z', 'I' }); fileStream.Write((int)(sizeof(int) + sizeof(int) * voxelsCount)); fileStream.Write((int)0); fileStream.Write((int)voxelsCount); voxelsNumber = 0; while ((material = iterator.GetNextMaterial(out x, out y, out z)) != null) { var column = voxels.Width - x - 1; var line = voxels.Depth - z - 1; var slice = y; if (column < maximumWidth && line < maximumHeight && slice < maximumSlice) { int sourceIndex = materialGroups[material]; int targetIndex = assignments[sourceIndex]; fileStream.Write((byte)column); fileStream.Write((byte)line); fileStream.Write((byte)slice); fileStream.Write((byte)(targetIndex + 1)); } if (++voxelsNumber % 1000 == 0) { progress = (float)voxelsNumber / (float)voxels.Count * 0.25f + 0.75f; yield return(null); } } // Store material colors to file fileStream.Write(new char[] { 'R', 'G', 'B', 'A' }); fileStream.Write((int)(sizeof(int) * 256)); fileStream.Write((int)0); for (int index = 0; index < outputMaterials.Length; ++index) { material = outputMaterials[index]; fileStream.Write((byte)(material.color.r * 255 + 0.5f)); fileStream.Write((byte)(material.color.g * 255 + 0.5f)); fileStream.Write((byte)(material.color.b * 255 + 0.5f)); fileStream.Write((byte)(material.color.a * 255 + 0.5f)); } // Fill unused colors for (int index = outputMaterials.Length; index < 256; ++index) { fileStream.Write((uint)0xFF000000); } // Store data size into file var endPointer = fileStream.BaseStream.Position; fileStream.Seek((int)sizePointer, SeekOrigin.Begin); fileStream.Write((int)(endPointer - sizePointer - sizeof(int))); // Close file stream fileStream.Close(); fileStream = null; } } // Finish function progress = 1; yield return(null); }