private static int ReadXYZI(BinaryReader br, MagicaVoxelMainChunk mainChunk) { int chunkSize = br.ReadInt32(); int childrenSize = br.ReadInt32(); if (childrenSize > 0) { br.ReadBytes(childrenSize); Debug.LogWarning("MV: Nested chunks not supported"); return(-1); } MagicaVoxelChunk chunk = mainChunk.chunk; int numVoxels = br.ReadInt32(); for (int i = 0; i < numVoxels; ++i) { int x = br.ReadByte(); int z = br.ReadByte(); // Magica has Z and Y swapped int y = br.ReadByte(); chunk.data[Helpers.GetIndex1DFrom3D(x, y, z, chunk.sizeX, chunk.sizeZ)] = br.ReadByte(); } return(chunkSize + childrenSize + 4 * 3); }
private static int ReadSize(BinaryReader br, MagicaVoxelMainChunk mainChunk) { int chunkSize = br.ReadInt32(); int childrenSize = br.ReadInt32(); if (childrenSize > 0) { br.ReadBytes(childrenSize); Debug.LogError("MV: Nested chunks not supported"); return(-1); } MagicaVoxelChunk chunk = mainChunk.chunk = new MagicaVoxelChunk(); chunk.sizeX = br.ReadInt32(); chunk.sizeZ = br.ReadInt32(); // Magica has Z and Y swapped chunk.sizeY = br.ReadInt32(); chunk.data = new byte[chunk.sizeX * chunk.sizeY * chunk.sizeZ]; return(chunkSize + childrenSize + 4 * 3); }
private static int ReadRGBA(BinaryReader br, MagicaVoxelMainChunk mainChunk) { int chunkSize = br.ReadInt32(); int childrenSize = br.ReadInt32(); if (childrenSize > 0) { br.ReadBytes(childrenSize); Debug.LogError("MV: Nested chunks not supported"); return(-1); } mainChunk.palette = new Color32[256]; mainChunk.palette[0] = new Color32(0, 0, 0, 0); for (int i = 1; i < 256; ++i) { mainChunk.palette[i] = new Color32( br.ReadByte(), br.ReadByte(), br.ReadByte(), br.ReadByte() ); } return(chunkSize + childrenSize + 4 * 3); }
/// <summary> /// Load a MagicaVoxel .vox format file into the custom ushort[] structure that we use for voxel chunks. /// </summary> /// <param name="br">An open BinaryReader stream that is the .vox file.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> public static MagicaVoxelMainChunk FromMagica(BinaryReader br) { // VOX file starts with 'VOX ' char[] chars = br.ReadChars(4); if (chars[0] != 'V' || chars[1] != 'O' || chars[2] != 'X' || chars[3] != ' ') { Debug.LogError("MV: Invalid file format. It does not start with 'VOX '"); return(null); } int version = br.ReadInt32(); if (version != 150) { Debug.LogWarning("MV: File version does not match 150. Issues possible."); } chars = br.ReadChars(4); if (chars[0] != 'M' || chars[1] != 'A' || chars[2] != 'I' || chars[3] != 'N') { Debug.LogError("MV: Invalid ChunkID, 'MAIN' expected"); return(null); } chars = br.ReadChars(4); if (chars[0] == 'P' && chars[1] == 'A' && chars[2] == 'C' && chars[3] == 'K') { Debug.LogError("MV: Multiple models for VOX not supported"); return(null); } // Main chunk data size in bytes int chunkSize = (chars[3] >> 24) | chars[2] >> 16 | chars[1] >> 8 | chars[0]; // Children chunk data size in bytes int childrenSize = br.ReadInt32(); if (childrenSize < 0) { Debug.LogError("MV: childrenSize < 0"); return(null); } // Main chunk should be empty. Let's skip it br.ReadBytes(chunkSize); MagicaVoxelMainChunk mainChunk = new MagicaVoxelMainChunk(); int readSize = 0; while (readSize < childrenSize) { // each chunk has an ID, size and child chunks chars = br.ReadChars(4); if (chars[0] == 'S' && chars[1] == 'I' && chars[2] == 'Z' && chars[3] == 'E') { int size = ReadSize(br, mainChunk); if (size < 0) { return(null); } readSize += size; } else if (chars[0] == 'X' && chars[1] == 'Y' && chars[2] == 'Z' && chars[3] == 'I') { int size = ReadXYZI(br, mainChunk); if (size < 0) { return(null); } readSize += size; } else if (chars[0] == 'R' && chars[1] == 'G' && chars[2] == 'B' && chars[3] == 'A') { int size = ReadRGBA(br, mainChunk); if (size < 0) { return(null); } readSize += size; } else { Debug.LogError("MV: Unrecognized file format"); return(null); } } // Use default palette if there is none in the file if (mainChunk.palette == null) { mainChunk.palette = new Color32[256]; for (int i = 0; i < 256; i++) { uint color = defaultPalette[i]; byte r = (byte)(color & 0xFF); byte g = (byte)((color >> 8) & 0xFF); byte b = (byte)((color >> 16) & 0xFF); byte a = (byte)((color >> 24) & 0xFF); mainChunk.palette[i] = new Color32(r, g, b, a); } } return(mainChunk); }