/// <summary> /// Count the size of all materials chunks /// </summary> /// <returns></returns> private int CountMaterialChunkSize() { int usedIndexColor = 0; Console.WriteLine("[LOG] Started to create an optimized palette..."); int globalIndex = 0; using (ProgressBar progressBar = new ProgressBar()) { for (int i = 0; i < _models.Count; i++) { VoxModel model = _models[i]; for (int j = 0; j < model.palette.Length; j++) { Color color = model.palette[j]; if (_usedColors.Count < 256 && !_usedColors.Contains(color) && color != Color.Empty && _models[i].colorUsed.Contains(j)) { _usedIndexColors[usedIndexColor] = new KeyValuePair <int, int>(i, j); _usedColors.Add(color); usedIndexColor++; } globalIndex++; progressBar.Report(globalIndex / (float)(_models.Count * 256)); } } } Console.WriteLine("[LOG] Done."); int size = 0; for (int i = 0; i < 256; i++) { if (_usedIndexColors.ContainsKey(i)) { KeyValuePair <int, int> modelIndex = _usedIndexColors[i]; if (_models[modelIndex.Key].materialChunks.Count > modelIndex.Value - 1) { size += Encoding.UTF8.GetByteCount(MATL) + 16; size += _models[modelIndex.Key].materialChunks[modelIndex.Value - 1].properties.Sum(keyValue => 8 + Encoding.UTF8.GetByteCount(keyValue.Key) + Encoding.UTF8.GetByteCount(keyValue.Value)); } } else { if (_models[0].materialChunks.Count > 0) { size += Encoding.UTF8.GetByteCount(MATL) + 16; size += _models[0].materialChunks[0].properties.Sum(keyValue => 8 + Encoding.UTF8.GetByteCount(keyValue.Key) + Encoding.UTF8.GetByteCount(keyValue.Value)); } } } return(size); }
private void CheckDuplicateChildGroupIds(VoxModel output) { List <int> childIds = output.groupNodeChunks.SelectMany(t => t.childIds).ToList(); List <int> duplicates = childIds.GroupBy(x => x) .Where(g => g.Count() > 1) .Select(y => y.Key) .ToList(); foreach (int id in duplicates) { Console.WriteLine("[ERROR] Duplicate child group ID: " + id); } }
public VoxModel LoadModel(string absolutePath, bool writeLog = false, bool debug = false) { VoxModel output = new VoxModel(); output.colorUsed = new HashSet <int>(); var name = Path.GetFileNameWithoutExtension(absolutePath); _voxelCountLastXYZIChunk = 0; _logOutputFile = name + "-" + DateTime.Now.ToString("y-MM-d_HH.m.s") + ".txt"; _writeLog = writeLog; using (var reader = new BinaryReader(new MemoryStream(File.ReadAllBytes(absolutePath)))) { var head = new string(reader.ReadChars(4)); if (!head.Equals(HEADER)) { Console.WriteLine("Not a Magicavoxel file! " + output); return(null); } int version = reader.ReadInt32(); if (version != VERSION) { Console.WriteLine("Version number: " + version + " Was designed for version: " + VERSION); } ResetModel(output); _childCount = 0; _chunkCount = 0; while (reader.BaseStream.Position != reader.BaseStream.Length) { ReadChunk(reader, output); } } if (debug) { CheckDuplicateIds(output); CheckDuplicateChildGroupIds(output); CheckTransformIdNotInGroup(output); Console.ReadKey(); } if (output.palette == null) { output.palette = LoadDefaultPalette(); } return(output); }
/// <summary> /// Clear model data /// </summary> /// <param name="model"></param> protected void ResetModel(VoxModel model) { if (model.voxelFrames != null) { model.voxelFrames.Clear(); } else { model.voxelFrames = new List <VoxelData>(); } model.materialChunks.Clear(); model.transformNodeChunks.Clear(); model.groupNodeChunks.Clear(); model.shapeNodeChunks.Clear(); model.layerChunks.Clear(); model.rendererSettingChunks.Clear(); }
private void CheckDuplicateIds(VoxModel output) { List <int> allIds = output.groupNodeChunks.Select(t => t.id).ToList(); allIds.AddRange(output.transformNodeChunks.Select(t => t.id)); allIds.AddRange(output.shapeNodeChunks.Select(t => t.id)); List <int> duplicates = allIds.GroupBy(x => x) .Where(g => g.Count() > 1) .Select(y => y.Key) .ToList(); foreach (int id in duplicates) { Console.WriteLine("[ERROR] Duplicate ID: " + id); } }
private void CheckTransformIdNotInGroup(VoxModel output) { List <int> ids = output.transformNodeChunks.Select(t => t.id).ToList(); List <int> childIds = output.groupNodeChunks.SelectMany(t => t.childIds).ToList(); List <int> empty = new List <int>(); foreach (int id in ids) { if (childIds.IndexOf(id) == -1 && id != 0) { empty.Add(id); } } foreach (int id in empty) { Console.WriteLine("[ERROR] Transform ID never called in any group: " + id); } }
/// <summary> /// Write XYZI chunk /// </summary> /// <param name="writer"></param> /// <param name="index"></param> private int WriteXyziChunk(BinaryWriter writer, VoxModel model, int index) { int byteWritten = 0; writer.Write(Encoding.UTF8.GetBytes(XYZI)); //int testA = (model.voxelFrames[index].Colors.Count(t => t != 0)); //int testB = model.voxelFrames[index].Colors.Length; writer.Write((model.voxelFrames[index].Colors.Count(t => t != 0) * 4) + 4); //XYZI chunk size writer.Write(0); //Child chunk size (constant) writer.Write(model.voxelFrames[index].Colors.Count(t => t != 0)); //Blocks count byteWritten += Encoding.UTF8.GetByteCount(XYZI) + 12; int count = 0; for (int y = 0; y < model.voxelFrames[index].VoxelsTall; y++) { for (int z = 0; z < model.voxelFrames[index].VoxelsDeep; z++) { for (int x = 0; x < model.voxelFrames[index].VoxelsWide; x++) { int paletteIndex = model.voxelFrames[index].Get(x, y, z); Color color = model.palette[paletteIndex]; if (color != Color.Empty) { writer.Write((byte)(x % model.voxelFrames[index].VoxelsWide)); writer.Write((byte)(y % model.voxelFrames[index].VoxelsTall)); writer.Write((byte)(z % model.voxelFrames[index].VoxelsDeep)); int i = _usedColors.IndexOf(color) + 1; writer.Write((i != 0) ? (byte)i : (byte)1); count++; byteWritten += 4; } } } } return(byteWritten); }
private void WriteLogs(string chunkName, int chunkSize, int childChunkSize, VoxModel output) { if (!Directory.Exists("logs")) { Directory.CreateDirectory("logs"); } string path = "logs/" + _logOutputFile; using (var writer = new StreamWriter(path, true)) { writer.WriteLine("CHUNK NAME: " + chunkName + " (" + _chunkCount + ")"); writer.WriteLine("CHUNK SIZE: " + chunkSize + " BYTES"); writer.WriteLine("CHILD CHUNK SIZE: " + childChunkSize); switch (chunkName) { case SIZE: var frame = output.voxelFrames[_childCount - 1]; writer.WriteLine("-> SIZE: " + frame.VoxelsWide + " " + frame.VoxelsTall + " " + frame.VoxelsDeep); break; case XYZI: writer.WriteLine("-> XYZI: " + _voxelCountLastXYZIChunk); break; case nTRN: var transform = output.transformNodeChunks.Last(); writer.WriteLine("-> TRANSFORM NODE: " + transform.id); writer.WriteLine("--> CHILD ID: " + transform.childId); writer.WriteLine("--> RESERVED ID: " + transform.reservedId); writer.WriteLine("--> LAYER ID: " + transform.layerId); DisplayAttributes(transform.attributes, writer); DisplayFrameAttributes(transform.frameAttributes, writer); break; case nGRP: var group = output.groupNodeChunks.Last(); writer.WriteLine("-> GROUP NODE: " + group.id); group.childIds.ToList().ForEach(t => writer.WriteLine("--> CHILD ID: " + t)); DisplayAttributes(group.attributes, writer); break; case nSHP: var shape = output.shapeNodeChunks.Last(); writer.WriteLine("-> SHAPE NODE: " + shape.id); DisplayAttributes(shape.attributes, writer); DisplayModelAttributes(shape.models, writer); break; case LAYR: var layer = output.layerChunks.Last(); writer.WriteLine("-> LAYER NODE: " + layer.id + " " + layer.Name + " " + layer.Hidden + " " + layer.unknown); DisplayAttributes(layer.attributes, writer); break; case MATL: var material = output.materialChunks.Last(); writer.WriteLine("-> MATERIAL NODE: " + material.id.ToString("F1")); writer.WriteLine("--> ALPHA: " + material.Alpha.ToString("F1")); writer.WriteLine("--> EMISSION: " + material.Emission.ToString("F1")); writer.WriteLine("--> FLUX: " + material.Flux.ToString("F1")); writer.WriteLine("--> METALLIC: " + material.Metallic.ToString("F1")); writer.WriteLine("--> ROUGH: " + material.Rough.ToString("F1")); writer.WriteLine("--> SMOOTHNESS: " + material.Smoothness.ToString("F1")); writer.WriteLine("--> SPEC: " + material.Spec.ToString("F1")); writer.WriteLine("--> WEIGHT: " + material.Weight.ToString("F1")); DisplayAttributes(material.properties, writer); break; } writer.WriteLine(""); writer.Close(); } }
private void ReadChunk(BinaryReader reader, VoxModel output) { var chunkName = new string(reader.ReadChars(4)); var chunkSize = reader.ReadInt32(); var childChunkSize = reader.ReadInt32(); var chunk = reader.ReadBytes(chunkSize); var children = reader.ReadBytes(childChunkSize); _chunkCount++; using (var chunkReader = new BinaryReader(new MemoryStream(chunk))) { switch (chunkName) { case MAIN: break; case SIZE: int w = chunkReader.ReadInt32(); int h = chunkReader.ReadInt32(); int d = chunkReader.ReadInt32(); if (_childCount >= output.voxelFrames.Count) { output.voxelFrames.Add(new VoxelData()); } output.voxelFrames[_childCount].Resize(w, h, d); _childCount++; break; case XYZI: _voxelCountLastXYZIChunk = chunkReader.ReadInt32(); var frame = output.voxelFrames[_childCount - 1]; byte x, y, z, color; for (int i = 0; i < _voxelCountLastXYZIChunk; i++) { x = chunkReader.ReadByte(); y = chunkReader.ReadByte(); z = chunkReader.ReadByte(); color = chunkReader.ReadByte(); frame.Set(x, y, z, color); output.colorUsed.Add(color); } break; case RGBA: output.palette = LoadPalette(chunkReader); break; case MATT: break; case PACK: int frameCount = chunkReader.ReadInt32(); for (int i = 0; i < frameCount; i++) { output.voxelFrames.Add(new VoxelData()); } break; case nTRN: output.transformNodeChunks.Add(ReadTransformNodeChunk(chunkReader)); break; case nGRP: output.groupNodeChunks.Add(ReadGroupNodeChunk(chunkReader)); break; case nSHP: output.shapeNodeChunks.Add(ReadShapeNodeChunk(chunkReader)); break; case LAYR: output.layerChunks.Add(ReadLayerChunk(chunkReader)); break; case MATL: output.materialChunks.Add(ReadMaterialChunk(chunkReader)); break; case rOBJ: output.rendererSettingChunks.Add(ReaddRObjectChunk(chunkReader)); break; default: Console.WriteLine($"Unknown chunk: \"{chunkName}\""); break; } } if (_writeLog) { WriteLogs(chunkName, chunkSize, childChunkSize, output); } //read child chunks using (var childReader = new BinaryReader(new MemoryStream(children))) { while (childReader.BaseStream.Position != childReader.BaseStream.Length) { ReadChunk(childReader, output); } } }