1 module voxd.vox; 2 3 import std.range, 4 std.file, 5 std.array, 6 std.string; 7 8 import voxd.utils; 9 10 /// Supports the VOX format used by MagicaVoxel 11 12 /// Decodes a VOX file. 13 /// Throws: VoxdException on error. 14 VOX decodeMagicaVOXFromFile(string filepath) 15 { 16 auto bytes = cast(ubyte[]) std.file.read(filepath); 17 return decodeMagicaVOXFromMemory(bytes); 18 } 19 20 /// Decodes a VOX. 21 /// Throws: VoxdException on error. 22 VOX decodeMagicaVOXFromMemory(ubyte[] input) 23 { 24 // check header 25 { 26 uint magic = popBE!uint(input); 27 if (magic != RIFFChunkId!"VOX ") 28 throw new VoxdException("Expected 'VOX ' chunk."); 29 30 immutable uint maxSupportedVersion = 150; 31 uint fileVersion = popLE!uint(input); 32 if (fileVersion > maxSupportedVersion) 33 throw new VoxdException(format("Unsupported version %s, maximum supported is %s", fileVersion, maxSupportedVersion)); 34 } 35 36 uint mainId; 37 uint mainSize; 38 getRIFFChunkHeader(input, mainId, mainSize); 39 if (mainId != RIFFChunkId!"MAIN") 40 throw new VoxdException("Expected MAIN chunk"); 41 42 long mainChildrenSize = popLE!uint(input); 43 44 // skip main 45 skipBytes(input, cast(int)mainSize); 46 47 // initialize palette 48 alias palette_t = VoxColor[256]; 49 palette_t palette; 50 for (int i = 0; i < 256; ++i) 51 palette[i] = VoxColor(defaultPalette[i]); 52 53 54 // default palette 55 int[] indices; 56 bool foundSizeChunk = false; 57 int width; 58 int height; 59 int depth; 60 61 while (mainChildrenSize > 0) 62 { 63 uint chunkId, chunkSize, childrenSize; 64 getRIFFChunkHeader(input, chunkId, chunkSize); 65 childrenSize = popLE!uint(input); 66 67 if (chunkId == RIFFChunkId!"SIZE") 68 { 69 width = popLE!int(input); 70 height = popLE!int(input); 71 depth = popLE!int(input); 72 73 indices.length = (width * height * depth); 74 indices[] = -1; 75 foundSizeChunk = true; 76 } 77 else if (chunkId == RIFFChunkId!"XYZI") 78 { 79 if (!foundSizeChunk) 80 throw new VoxdException("Expected SIZE chunk before XYZI chunk"); 81 82 uint numVoxels = popLE!uint(input); 83 84 if (chunkSize != 4 + numVoxels * 4) 85 throw new VoxdException("Incorrect XYZI chunk size"); 86 87 for (uint i = 0; i < numVoxels; ++i) 88 { 89 int x = popUbyte(input); 90 int y = popUbyte(input); 91 int z = popUbyte(input); 92 ubyte c = popUbyte(input); 93 if (c == 0) 94 throw new VoxdException("Color 0 encountered"); 95 96 indices[x + y * width + z *width * height] = c - 1; 97 } 98 } 99 else if (chunkId == RIFFChunkId!"RGBA") 100 { 101 if (chunkSize != 256 * 4) 102 throw new VoxdException("Incorrect RGBA chunk size"); 103 104 for (int i = 0; i < 256; ++i) 105 palette[i] = VoxColor(popLE!uint(input)); 106 } 107 108 // skip children size 109 skipBytes(input, childrenSize); 110 111 mainChildrenSize -= (chunkSize + childrenSize + 12); 112 } 113 114 if (!foundSizeChunk) 115 throw new VoxdException("Expected SIZE chunk"); 116 117 VOX result; 118 119 result.width = width; 120 result.height = height; 121 result.depth = depth; 122 result.voxels.length = width * height * depth; 123 124 for (int i = 0; i < width * height * depth; ++i) 125 { 126 if (indices[i] == -1) 127 result.voxels[i] = VoxColor(0); 128 else 129 result.voxels[i] = palette[indices[i]]; 130 } 131 132 return result; 133 } 134 135 private 136 { 137 138 139 140 struct MV_Voxel 141 { 142 ubyte x, y, z, colorIndex; 143 } 144 145 static immutable uint[256] defaultPalette = 146 [ 147 0x00000000, 0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff, 148 0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff, 149 0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc, 150 0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc, 151 0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99, 152 0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699, 153 0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66, 154 0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666, 155 0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066, 156 0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933, 157 0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033, 158 0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00, 159 0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300, 160 0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044, 161 0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000, 162 0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111 163 ]; 164 }