/// <summary> /// Load a MagicaVoxel .vox format file into the custom ushort[] structure that we use for voxel chunks. /// </summary> /// <param name="stream">An open BinaryReader stream that is the .vox file.</param> /// <param name="overrideColors">Optional color lookup table for converting RGB values into my internal engine color format.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> private static Color32[] FromMagica(BinaryReader stream, out Vector3Int size) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] data = null; // new Color32[32 * 128 * 32]; // new ushort[32 * 128 * 32]; Color32[] colors = null; MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); /*int version = */ stream.ReadInt32(); // never used, just advance stream cursor // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier int sizex = 0, sizey = 0, sizez = 0; size = new Vector3Int(0, 0, 0); if (magic == "VOX ") { bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); /*int childChunks = */ stream.ReadInt32(); // never used but we should advance the cursor string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { // in magica voxel z is up. // in voxel play y is up. // swap z and y sizex = stream.ReadInt32(); sizez = stream.ReadInt32(); sizey = stream.ReadInt32(); if (sizex > 32 || sizey > 32) { subsample = true; } stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); //int div = (subsample ? 2 : 1); //never used // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } } else if (chunkName == "RGBA") { colors = new Color32[256]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); /*byte a = */ stream.ReadByte(); // never used. advance cursor colors[i] = new Color32(r, g, b, 255); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } data = new Color32[sizex * sizey * sizez]; if (voxelData.Length == 0) { return(data); // failed to read any valid voxel data } if (sizex == 0 || sizey == 0 || sizez == 0) { return(data); } if (colors == null) { Debug.LogWarning("no colors array"); } else { Debug.Log("colors len: " + colors.Length); } // now push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].x > 31 || voxelData[i].y > 127 || voxelData[i].z > 31) { continue; } // use the voxColors array by default, or overrideColor if it is available int voxel = voxelData[i].x + voxelData[i].z * sizex + voxelData[i].y * sizex * sizez; Color32 c; if (colors != null) { c = colors[voxelData[i].color - 1]; } else { c = FromUShortColor(voxColors[voxelData[i].color - 1]); } data[voxel] = c; } } size = new Vector3Int(sizex, sizey, sizez); return(data); }
/// <summary> /// Load a MagicaVoxel .vox format file into the custom ushort[] structure that we use for voxel chunks. /// </summary> /// <param name="stream">An open BinaryReader stream that is the .vox file.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> public static Result ReadFile(BinaryReader stream) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data ushort[] data = new ushort[32 * 128 * 32]; Color[] colors = null; Result resultObject = new Result(); MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { resultObject.sizeX = stream.ReadInt32(); resultObject.sizeY = stream.ReadInt32(); resultObject.sizeZ = stream.ReadInt32(); stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream); } } else if (chunkName == "RGBA") { colors = new Color[256]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); //Store custom color palette colors[i] = new Color(r / 255f, g / 255f, b / 255f, a); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return(resultObject); } resultObject.voxels = new VoxelData[voxelData.Length]; for (int i = 0; i < voxelData.Length; i++) { resultObject.voxels[i] = new VoxelData(voxelData[i].x, voxelData[i].y, voxelData[i].z, colors == null ? getColor(defaultPallet[voxelData[i].color]) : colors[voxelData[i].color - 1]); } } return(resultObject); }
/// <summary> /// Load a MagicaVoxel .vox format file into the custom ushort[] structure that we use for voxel chunks. /// </summary> /// <param name="stream">An open BinaryReader stream that is the .vox file.</param> /// <param name="overrideColors">Optional color lookup table for converting RGB values into my internal engine color format.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> private static Color32[] FromMagica(BinaryReader stream) { // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier string magic = new string(stream.ReadChars(4)); if (magic != "VOX ") { return(null); } int version = stream.ReadInt32(); if (version != 150) { Debug.LogWarning("Vox file version does not match 150. Issues possible."); } // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] data = new Color32[SizeX * SizeY * SizeZ]; Color32[] colors = null; MagicaVoxelData[] voxelData = null; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); if (childChunks < 0) { Debug.LogError("childChunks < 0"); return(null); } string chunkName = new string(chunkId); switch (chunkName) { // Chunk dimensions case "SIZE": { int sizeX = stream.ReadInt32(); int sizeY = stream.ReadInt32(); int sizeZ = stream.ReadInt32(); if (sizeX > SizeX || sizeZ > SizeZ || sizeY > SizeY) { subsample = true; } stream.ReadBytes(chunkSize - 4 * 3); break; } // Voxel data case "XYZI": { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); if (numVoxels <= 0) { return(null); } //int div = (subsample ? 2 : 1); // Each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } break; } case "RGBA": { colors = new Color32[256]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // Convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r, g, b, a); //(ushort) (((r & 0x1f) << 10) | ((g & 0x1f) << 5) | (b & 0x1f)); } break; } default: // Read any excess bytes stream.ReadBytes(chunkSize); break; } } // Failed to read any valid voxel data if (voxelData == null || voxelData.Length == 0) { return(null); } // Push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // Do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].X >= SizeX || voxelData[i].Y >= SizeY || voxelData[i].Z >= SizeZ) { continue; } // Use the voxColors array by default, or overrideColor if it is available int voxel = (voxelData[i].X + (voxelData[i].Z << LogX) + (voxelData[i].Y << LogY << LogZ)); if (colors == null) { uint col = SVoxColors[voxelData[i].Color - 1]; data[voxel] = new Color32((byte)((col >> 16) & 0xFf), (byte)((col >> 8) & 0xFf), (byte)(col & 0xFf), 0xFf); } else { data[voxel] = colors[voxelData[i].Color - 1]; } } return(data); }
/// <summary> /// Load a MagicaVoxel .vox format file into the custom ushort[] structure that we use for voxel chunks. /// </summary> /// <param name="stream">An open BinaryReader stream that is the .vox file.</param> /// <param name="overrideColors">Optional color lookup table for converting RGB values into my internal engine color format.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> private static byte[] LoadFromStream(BinaryReader stream) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // Initialize null byte byte[] data = new byte[1]; uint[] colors = null; MagicaVoxelData[] voxelData = null; // Initialize min and max bounding box extents int[] extents = new int[6] { 256, 256, 256, 0, 0, 0 }; string magic = new string(stream.ReadChars(4)); int version = stream.ReadInt32(); int numVoxels = 0; // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizey = stream.ReadInt32(); sizez = stream.ReadInt32(); if (sizex > 32 || sizey > 32) { subsample = true; } stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels numVoxels = stream.ReadInt32(); int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; // Set up data array. First 768 bytes are for the color palette // Last 6 bytes are for model bounds data = new byte[numVoxels * 4 + colorPaletteSize * 3 + 6]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } } else if (chunkName == "RGBA") { colors = new uint[colorPaletteSize]; for (int i = 0; i < colorPaletteSize; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to 24-bit RGB colors[i] = (uint)((r << 16) | (g << 8) | b); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return(data); // failed to read any valid voxel data } // Copy color palette into data array for (int i = 0; i < colors.Length; i++) { data[i * 3] = (byte)(colors[i] >> 16); data[i * 3 + 1] = (byte)(colors[i] >> 8); data[i * 3 + 2] = (byte)(colors[i]); } int offset = 0; // now push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].x > 31 || voxelData[i].y > 31 || voxelData[i].z > 127) { continue; } offset = (colorPaletteSize * 3) + (i * 4); data[offset + 1] = (byte)voxelData[i].y; data[offset + 2] = (byte)voxelData[i].x; data[offset + 3] = (byte)voxelData[i].z; data[offset] = (byte)(voxelData[i].color - 1); // Update extents metadata extents[0] = (voxelData[i].y < extents[0]) ? voxelData[i].y : extents[0]; extents[1] = (voxelData[i].x < extents[1]) ? voxelData[i].x : extents[1]; extents[2] = (voxelData[i].z < extents[2]) ? voxelData[i].z : extents[2]; extents[3] = (voxelData[i].y > extents[3]) ? voxelData[i].y : extents[3]; extents[4] = (voxelData[i].x > extents[4]) ? voxelData[i].x : extents[4]; extents[5] = (voxelData[i].z > extents[5]) ? voxelData[i].z : extents[5]; } // Add extents metadata offset = (numVoxels * 4) + (colorPaletteSize * 3); for (int i = 0; i < 6; i++) { data[offset + i] = (byte)(extents[i] + 1); } } return(data); }
public static Chunk LoadModel(string filename, string type) { BinaryReader stream = new BinaryReader(File.Open(filename, FileMode.Open)); int[] colors = null; MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); int version = stream.ReadInt32(); int sizex = 0, sizey = 0, sizez = 0; if (magic == "VOX ") { bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizey = stream.ReadInt32(); sizez = stream.ReadInt32(); //if (sizex > 32 || sizey > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData [i] = new MagicaVoxelData(stream, false); } } else if (chunkName == "RGBA") { colors = new int[256]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = (int)(((r & 0xFF) << 24) | ((g & 0xFF) << 16) | (b & 0xFF) << 8); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return(null); // failed to read any valid voxel data } // now push the voxel data into our voxel chunk structure if (type == "map") { int scale = 3; World.width = (int)(sizex * scale) / World.chunkSize; World.height = (int)(sizez * scale) / World.chunkSize; World.depth = (int)(sizey * scale) / World.chunkSize; World.CreateChunks(); int c = 0; for (int i = 0; i < voxelData.Length; i++) { c++; int col = (colors == null ? voxColors [voxelData [i].color - 1] : colors [voxelData [i].color - 1]); for (int x1 = voxelData[i].x * (scale - 1) + 1; x1 < voxelData[i].x * (scale - 1) + scale; x1++) { for (int z1 = voxelData[i].z * (scale - 1) + 1; z1 < voxelData[i].z * (scale - 1) + scale; z1++) { for (int y1 = voxelData[i].y * (scale - 1) + 1; y1 < voxelData[i].y * (scale - 1) + scale; y1++) { World.blocks [x1, z1, y1] = col; } } } } World.RebuildDirtyChunks(true); return(null); } else { Chunk c = new Chunk(); c.type = Chunk.TYPE_OBJ; c.EnableObject(sizex, sizez, sizey); for (int i = 0; i < voxelData.Length; i++) { int col = (colors == null ? voxColors [voxelData [i].color - 1] : colors [voxelData [i].color - 1]); c.blocks [voxelData [i].x, voxelData [i].z, voxelData [i].y] = col; } World.RebuildChunks(c); stream.Close(); return(c); } } return(null); }
public async Task ReadMagica(Stream stream) { int[] colors = null; MagicaVoxelData[] voxelData = null; String magic = new String(ReadChars(stream, 4)); int version = ReadInt32(stream); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic.CompareTo("VOX ") == 0) { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.Position < stream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = ReadChars(stream, 4); int chunkSize = ReadInt32(stream); int childChunks = ReadInt32(stream); String chunkName = new String(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName.CompareTo("SIZE") == 0) { sizex = ReadInt32(stream); sizey = ReadInt32(stream); sizez = ReadInt32(stream); if (sizex > 32 || sizey > 32) subsample = true; stream.Seek(chunkSize - 4 * 3, SeekOrigin.Current); } else if (chunkName.CompareTo("XYZI") == 0) { // XYZI contains n voxels int numVoxels = ReadInt32(stream); int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) voxelData[i] = new MagicaVoxelData(stream, subsample); } else if (chunkName.CompareTo("RGBA") == 0) { colors = new int[256]; for (int i = 0; i < 256; i++) { int r = stream.ReadByte() & 0xff; int g = stream.ReadByte() & 0xff; int b = stream.ReadByte() & 0xff; int a = stream.ReadByte() & 0xff; colors[i] = (a & 0xff) << 24 | (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff); } } else stream.Seek(chunkSize, SeekOrigin.Current); // read any excess bytes } if (voxelData.Length == 0) return; // now push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].x > 31 || voxelData[i].y > 31 || voxelData[i].z > 127) continue; int color = 0; if (colors == null) // use default palette { // WTF hardcoded palette is ABGR, doing ABGR => ARGB color = (int)voxColors[voxelData[i].color - 1]; int r = color & 0xff; int g = (color >> 8) & 0xff; int b = (color >> 16) & 0xff; int a = (color >> 28) & 0xff; color = a << 28 | r << 16 | g << 8 | b; } else // use palette from file { color = colors[voxelData[i].color - 1]; } if (timelapse) await Task.Delay(2); if (BlockConstructed != null) { Vector3 position = new Vector3(voxelData[i].x, voxelData[i].y, voxelData[i].z); BlockConstructed(new Tuple<Vector3, int>(position, color)); } } } }
private void LoadVoxFile(string aFileName) { //I dissabled compiler warning, because we want to load some values from the file even if we would not use it later. //I think it is cleaner this way #pragma warning disable //Prepare Object GameObject newGameObject = new GameObject(); newGameObject.name = "ImportedFromMagicaVoxel"; VoxelContainer newVoxelContainer = newGameObject.AddComponent <VoxelContainer>(); //Open File BinaryReader br = new BinaryReader(File.OpenRead(aFileName)); string magic = new string(br.ReadChars(4)); int version = br.ReadInt32(); if (magic == "VOX ") { int sizex = 0, sizey = 0, sizez = 0; Color[] colors = null; MagicaVoxelData[] voxelData = null; while (br.BaseStream.Position < br.BaseStream.Length) { char[] chunkId = br.ReadChars(4); int chunkSize = br.ReadInt32(); int childChunks = br.ReadInt32(); string chunkName = new string(chunkId); if (chunkName == "SIZE") { sizex = br.ReadInt32(); sizey = br.ReadInt32(); sizez = br.ReadInt32(); br.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { int numVoxels = br.ReadInt32(); voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(br); } } else if (chunkName == "RGBA") { colors = new Color[256]; for (int i = 0; i < 256; i++) { byte r = br.ReadByte(); byte g = br.ReadByte(); byte b = br.ReadByte(); byte a = br.ReadByte(); colors[i].r = r / 255f; colors[i].g = g / 255f; colors[i].b = b / 255f; colors[i].a = a / 255f; } } else { br.ReadBytes(chunkSize); } } if ((voxelData == null) || (voxelData.Length == 0)) { return; } for (int i = 0; i < voxelData.Length; i++) { Vector3 position = new Vector3(voxelData[i].x, voxelData[i].z, voxelData[i].y); if (!newVoxelContainer.voxels.ContainsKey(position)) { Voxel newVoxel = new Voxel(); newVoxel.position = position; newVoxel.color = (colors == null ? UShortToColor(voxColors[voxelData[i].color - 1]) : colors[voxelData[i].color - 1]); newVoxelContainer.AddVoxel(newVoxel, false); } } newVoxelContainer.UpdateStructure(); newVoxelContainer.BuildMesh(true, true, true, true); } else { Debug.LogError("Error durring vox import. Probably this is not a .vox file."); return; } #pragma warning restore }
public static void FromMagica(BinaryReader stream, GameObject root, float voxelSize, bool centerPivot) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] colors = new Color32[256]; for (int i = 1; i < 256; i++) { uint hexval = defaultColors[i]; byte cb = (byte)((hexval >> 16) & 0xFF); byte cg = (byte)((hexval >> 8) & 0xFF); byte cr = (byte)((hexval >> 0) & 0xFF); colors[i - 1] = new Color32(cr, cg, cb, 255); } MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); //int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); //int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizez = stream.ReadInt32(); sizey = stream.ReadInt32(); //if (sizex > 32 || sizey > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) voxelData[i] = new MagicaVoxelData(stream, subsample); } else if (chunkName == "RGBA") { for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r, g, b, a); } } else stream.ReadBytes(chunkSize); // read any excess bytes } if (voxelData.Length == 0) return; // failed to read any valid voxel data if (root != null) { Volume voxelVolume = root.GetComponent<Volume>(); voxelVolume.XSize = sizex; voxelVolume.YSize = sizey; voxelVolume.ZSize = sizez; voxelVolume.Frames[0].XSize = sizex; voxelVolume.Frames[0].YSize = sizey; voxelVolume.Frames[0].ZSize = sizez; voxelVolume.Frames[0].Voxels = new Voxel[sizex * sizey * sizez]; for (int i = 0; i < voxelVolume.Frames[0].Voxels.Length; i++) voxelVolume.Frames[0].Voxels[i].Value = 128; voxelVolume.VoxelSize = voxelSize; if (centerPivot) { voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, voxelVolume.YSize, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); } foreach (MagicaVoxelData v in voxelData) { try { voxelVolume.Frames[0].Voxels[v.x + sizex * (v.z + sizey * v.y)] = new Voxel() { State = VoxelState.Active, Color = colors[v.color-1], Value = 128 }; } catch (Exception) { Debug.Log(v.x + " " + v.y + " " + v.z); } } voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); } } }
private static Bitmap renderH(MagicaVoxelData[] voxels, int facing, int frame, int maxFrames, bool still, bool darkOutline) { Bitmap bmp = new Bitmap(vwidth * 16, vheight * 16, PixelFormat.Format32bppArgb); // Specify a pixel format. PixelFormat pxf = PixelFormat.Format32bppArgb; // Lock the bitmap's bits. Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, pxf); // Get the address of the first line. IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap. // int numBytes = bmp.Width * bmp.Height * 3; int numBytes = bmpData.Stride * bmp.Height; byte[] argbValues = new byte[numBytes]; argbValues.Fill <byte>(0); byte[] shadowValues = new byte[numBytes]; shadowValues.Fill <byte>(0); byte[] outlineColors = new byte[numBytes]; outlineColors.Fill <byte>(0); byte[] outlineValues = new byte[numBytes]; outlineValues.Fill <byte>(0); bool[] barePositions = new bool[numBytes]; barePositions.Fill <bool>(false); int xSize = 16, ySize = 16; MagicaVoxelData[] vls = new MagicaVoxelData[voxels.Length]; switch (facing) { case 0: vls = voxels; break; case 1: for (int i = 0; i < voxels.Length; i++) { byte tempX = (byte)(voxels[i].x - (xSize / 2)); byte tempY = (byte)(voxels[i].y - (ySize / 2)); vls[i].x = (byte)((tempY) + (ySize / 2)); vls[i].y = (byte)((tempX * -1) + (xSize / 2) - 1); vls[i].z = voxels[i].z; vls[i].color = voxels[i].color; } break; case 2: for (int i = 0; i < voxels.Length; i++) { byte tempX = (byte)(voxels[i].x - (xSize / 2)); byte tempY = (byte)(voxels[i].y - (ySize / 2)); vls[i].x = (byte)((tempX * -1) + (xSize / 2) - 1); vls[i].y = (byte)((tempY * -1) + (ySize / 2) - 1); vls[i].z = voxels[i].z; vls[i].color = voxels[i].color; } break; case 3: for (int i = 0; i < voxels.Length; i++) { byte tempX = (byte)(voxels[i].x - (xSize / 2)); byte tempY = (byte)(voxels[i].y - (ySize / 2)); vls[i].x = (byte)((tempY * -1) + (ySize / 2) - 1); vls[i].y = (byte)(tempX + (xSize / 2)); vls[i].z = voxels[i].z; vls[i].color = voxels[i].color; } break; } int[] xbuffer = new int[numBytes]; xbuffer.Fill <int>(-999); int[] zbuffer = new int[numBytes]; zbuffer.Fill <int>(-999); int jitter = (((frame % 4) % 3) + ((frame % 4) / 3)) * 2; if (maxFrames >= 8) { jitter = ((frame % 8 > 4) ? 4 - ((frame % 8) ^ 4) : frame % 8); } foreach (MagicaVoxelData vx in vls.OrderByDescending(v => v.x * 40 - v.y + v.z * 40 * 40 - ((VoxelLogic.WithoutShadingK(v.color) == 23) ? 40 * 40 * 40 : 0))) //voxelData[i].x + voxelData[i].z * 32 + voxelData[i].y * 32 * 128 { int unshaded = VoxelLogic.WithoutShadingK(vx.color); int current_color = ((255 - vx.color) % 4 == 0) ? (255 - vx.color) / 4 + hcolorcount : ((254 - vx.color) % 4 == 0) ? (253 - clear) / 4 : (253 - vx.color) / 4; bool is_shaded = (unshaded != current_color); int p = 0; if ((255 - vx.color) % 4 != 0 && (253 - vx.color) % 4 != 0) { continue; } if ((255 - vx.color) % 4 != 0 && current_color >= hcolorcount) { continue; } if (unshaded == hcolorcount - 1) { for (int j = 0; j < vheight; j++) { for (int i = 0; i < 4 * vwidth; i++) { p = voxelToPixelH16(i, j, vx.x, vx.y, vx.z, current_color, bmpData.Stride, jitter, still); if (shadowValues[p] == 0) { shadowValues[p] = hrendered[current_color][i + j * (vwidth * 4)]; } } } } else { for (int j = 0; j < vheight; j++) { for (int i = 0; i < 4 * vwidth; i++) { p = voxelToPixelH16(i, j, vx.x, vx.y, vx.z, current_color, bmpData.Stride, jitter, still); if (argbValues[p] == 0) { zbuffer[p] = vx.z; xbuffer[p] = vx.x; argbValues[p] = hrendered[current_color][i + j * (vwidth * 4)]; if (outlineColors[p] == 0) { outlineColors[p] = hrendered[current_color][i + (4 * vwidth * vheight)]; //(argbValues[p] * 1.2 + 2 < 255) ? (byte)(argbValues[p] * 1.2 + 2) : (byte)255; } } } } } } /* * for (int i = 3; i < numBytes; i += 4) * { * if (argbValues[i] > 255 * waver_alpha) * { * if (i + 4 >= 0 && i + 4 < argbValues.Length && argbValues[i + 4] == 0 && darkOutline && outlineValues[i + 4] == 0) { outlineValues[i + 4] = 255; } else if (i + 4 >= 0 && i + 4 < argbValues.Length && barePositions[i + 4] == false && (zbuffer[i] - 1 > zbuffer[i + 4] || xbuffer[i] - 1 > xbuffer[i + 4]) && outlineValues[i + 4] == 0) { outlineValues[i + 4] = 255; outlineValues[i + 4 - 1] = outlineColors[i - 1]; outlineValues[i + 4 - 2] = outlineColors[i - 2]; outlineValues[i + 4 - 3] = outlineColors[i - 3]; } * if (i - 4 >= 0 && i - 4 < argbValues.Length && argbValues[i - 4] == 0 && darkOutline && outlineValues[i - 4] == 0) { outlineValues[i - 4] = 255; } else if (i - 4 >= 0 && i - 4 < argbValues.Length && barePositions[i - 4] == false && (zbuffer[i] - 1 > zbuffer[i - 4] || xbuffer[i] - 1 > xbuffer[i - 4]) && outlineValues[i - 4] == 0) { outlineValues[i - 4] = 255; outlineValues[i - 4 - 1] = outlineColors[i - 1]; outlineValues[i - 4 - 2] = outlineColors[i - 2]; outlineValues[i - 4 - 3] = outlineColors[i - 3]; } * if (i + bmpData.Stride >= 0 && i + bmpData.Stride < argbValues.Length && argbValues[i + bmpData.Stride] == 0 && darkOutline && outlineValues[i + bmpData.Stride] == 0) { outlineValues[i + bmpData.Stride] = 255; } else if (i + bmpData.Stride >= 0 && i + bmpData.Stride < argbValues.Length && barePositions[i + bmpData.Stride] == false && (zbuffer[i] - 1 > zbuffer[i + bmpData.Stride] || xbuffer[i] - 1 > xbuffer[i + bmpData.Stride]) && outlineValues[i + bmpData.Stride] == 0) { outlineValues[i + bmpData.Stride] = 255; outlineValues[i + bmpData.Stride - 1] = outlineColors[i - 1]; outlineValues[i + bmpData.Stride - 2] = outlineColors[i - 2]; outlineValues[i + bmpData.Stride - 3] = outlineColors[i - 3]; } * if (i - bmpData.Stride >= 0 && i - bmpData.Stride < argbValues.Length && argbValues[i - bmpData.Stride] == 0 && darkOutline && outlineValues[i - bmpData.Stride] == 0) { outlineValues[i - bmpData.Stride] = 255; } else if (i - bmpData.Stride >= 0 && i - bmpData.Stride < argbValues.Length && barePositions[i - bmpData.Stride] == false && (zbuffer[i] - 1 > zbuffer[i - bmpData.Stride] || xbuffer[i] - 1 > xbuffer[i - bmpData.Stride]) && outlineValues[i - bmpData.Stride] == 0) { outlineValues[i - bmpData.Stride] = 255; outlineValues[i - bmpData.Stride - 1] = outlineColors[i - 1]; outlineValues[i - bmpData.Stride - 2] = outlineColors[i - 2]; outlineValues[i - bmpData.Stride - 3] = outlineColors[i - 3]; } * } * } */ for (int i = 3; i < numBytes; i += 4) { if (argbValues[i] > 0) { argbValues[i] = 255; } if (outlineValues[i] == 255) { argbValues[i] = 255; argbValues[i - 1] = outlineValues[i - 1]; argbValues[i - 2] = outlineValues[i - 2]; argbValues[i - 3] = outlineValues[i - 3]; } } for (int s = 3; s < numBytes; s += 4) { if (shadowValues[s] > 0) { if (argbValues[s] == 0) { argbValues[s - 3] = shadowValues[s - 3]; argbValues[s - 2] = shadowValues[s - 2]; argbValues[s - 1] = shadowValues[s - 1]; argbValues[s - 0] = shadowValues[s - 0]; } } } /* * for (int s = 3; s < numBytes; s += 4) * { * if (shadowValues[s] > 0) * { * foreach (int i in new int[]{ s + 4, s - 4, s + bmpData.Stride, s - bmpData.Stride * //, s + bmpData.Stride + 4, s - bmpData.Stride + 4, s + bmpData.Stride - 4, s - bmpData.Stride - 4 * }) * { * if (i >= 3 && i < argbValues.Length && argbValues[i] == 0) * { * argbValues[i - 3] = (byte)(shadowValues[s - 3] + 50); * argbValues[i - 2] = (byte)(shadowValues[s - 2] + 50); * argbValues[i - 1] = (byte)(shadowValues[s - 1] + 50); * argbValues[i - 0] = shadowValues[s - 0]; * } * } * } * }*/ Marshal.Copy(argbValues, 0, ptr, numBytes); // Unlock the bits. bmp.UnlockBits(bmpData); return(bmp); }
private static MagicaVoxelData[] FromMagica(BinaryReader stream) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizey = stream.ReadInt32(); sizez = stream.ReadInt32(); //if (sizex > 32 || sizey > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) voxelData[i] = new MagicaVoxelData(stream); } else if (chunkName == "RGBA") { //colors = new float[256][]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); } } else stream.ReadBytes(chunkSize); // read any excess bytes } if (voxelData.Length == 0) return voxelData; // failed to read any valid voxel data } return voxelData; }
public static void FromMagica(BinaryReader stream, GameObject root, float voxelSize, bool centerPivot) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] colors = new Color32[256]; for (int i = 1; i < 256; i++) { uint hexval = defaultColors[i]; byte cb = (byte)((hexval >> 16) & 0xFF); byte cg = (byte)((hexval >> 8) & 0xFF); byte cr = (byte)((hexval >> 0) & 0xFF); colors[i - 1] = new Color32(cr, cg, cb, 255); } MagicaVoxelData[] voxelData = null; List <MagicaVoxelData[]> frames = new List <MagicaVoxelData[]>(); //int numFrames = 1; string magic = new string(stream.ReadChars(4)); //int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); //int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); if (chunkName == "PACK") { stream.ReadInt32(); } else if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizez = stream.ReadInt32(); sizey = stream.ReadInt32(); //if (sizex > 32 || sizey > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } frames.Add(voxelData); } else if (chunkName == "RGBA") { for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r, g, b, a); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return; // failed to read any valid voxel data } if (root != null) { Volume voxelVolume = root.GetComponent <Volume>(); voxelVolume.XSize = sizex; voxelVolume.YSize = sizey; voxelVolume.ZSize = sizez; voxelVolume.Frames[voxelVolume.CurrentFrame].XSize = sizex; voxelVolume.Frames[voxelVolume.CurrentFrame].YSize = sizey; voxelVolume.Frames[voxelVolume.CurrentFrame].ZSize = sizez; voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels = new Voxel[sizex * sizey * sizez]; for (int i = 0; i < voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels.Length; i++) { voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels[i].Value = 128; } voxelVolume.VoxelSize = voxelSize; if (centerPivot) { voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, voxelVolume.YSize, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); } foreach (MagicaVoxelData[] d in frames) { foreach (MagicaVoxelData v in d) { try { voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels[v.x + sizex * (v.z + sizey * v.y)] = new Voxel() { State = VoxelState.Active, Color = colors[v.color - 1], Value = 128 }; } catch (Exception) { Debug.Log(v.x + " " + v.y + " " + v.z); } } if (frames.IndexOf(d) < frames.Count - 1) { voxelVolume.AddFrame(voxelVolume.CurrentFrame + 1); voxelVolume.Frames[voxelVolume.CurrentFrame].Voxels = new Voxel[sizex * sizey * sizez]; } } voxelVolume.SetFrame(0); voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); } } }
public static Bitmap drawPixelsN(MagicaVoxelData[] voxels) { Bitmap b = new Bitmap(22, 44); Graphics g = Graphics.FromImage((Image)b); //Image image = new Bitmap("cube_large.png"); Image image = new Bitmap("cube_ortho.png"); //Image reversed = new Bitmap("cube_reversed.png"); ImageAttributes imageAttributes = new ImageAttributes(); int width = 1; int height = 2; //g.DrawImage(image, 10, 10, width, height); float[][] colorMatrixElements = { new float[] { 1F, 0, 0, 0, 0 }, new float[] { 0, 1F, 0, 0, 0 }, new float[] { 0, 0, 1F, 0, 0 }, new float[] { 0, 0, 0, 1F, 0 }, new float[] { 0, 0, 0, 0, 1F } }; ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements); imageAttributes.SetColorMatrix( colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); MagicaVoxelData[] vls = new MagicaVoxelData[voxels.Length]; for (int i = 0; i < voxels.Length; i++) { byte tempX = (byte)(voxels[i].x - 11); byte tempY = (byte)(voxels[i].y - 11); vls[i].x = (byte)((tempX * -1) + 11 - 1); vls[i].y = (byte)((tempY * -1) + 11 - 1); vls[i].z = voxels[i].z; vls[i].color = voxels[i].color; } foreach (MagicaVoxelData vx in vls.OrderBy(v => v.x * 32 - v.y + v.z * 32 * 128)) //voxelData[i].x + voxelData[i].z * 32 + voxelData[i].y * 32 * 128 { int current_color = 249 - vx.color; if (current_color > 128) { current_color = 24; } colorMatrix = new ColorMatrix(new float[][] { new float[] { colors[current_color][0], 0, 0, 0, 0 }, new float[] { 0, colors[current_color][1], 0, 0, 0 }, new float[] { 0, 0, colors[current_color][2], 0, 0 }, new float[] { 0, 0, 0, 1F, 0 }, new float[] { 0, 0, 0, 0, 1F } }); imageAttributes.SetColorMatrix( colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage( image, new Rectangle(vx.y, 44 - 1 - 20 - 2 + vx.x - vx.z, width, height), // destination rectangle // new Rectangle((vx.x + vx.y) * 4, 128 - 6 - 32 - vx.y * 2 + vx.x * 2 - 4 * vx.z, width, height), // destination rectangle 0, 0, // upper-left corner of source rectangle width, // width of source rectangle height, // height of source rectangle GraphicsUnit.Pixel, imageAttributes); } return(b); }
/// <summary> /// Load a MagicaVoxel .vox format file into a MagicaVoxelData[] that we use for voxel chunks. /// </summary> /// <param name="stream">An open BinaryReader stream that is the .vox file.</param> /// <param name="overrideColors">Optional color lookup table for converting RGB values into my internal engine color format.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> public static MagicaVoxelData[] FromMagica(BinaryReader stream) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data ushort[] data = new ushort[32 * 128 * 32]; MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizey = stream.ReadInt32(); sizez = stream.ReadInt32(); if (sizex > 32 || sizey > 32) { subsample = true; } stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } } else if (chunkName == "RGBA") { // colors = new float[256][]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); //colors[i] = new float[] { r / 256.0f, g / 256.0f, b / 256.0f, a / 256.0f}; } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return(voxelData); // failed to read any valid voxel data } // now push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].x > 31 || voxelData[i].y > 31 || voxelData[i].z > 127) { continue; } // use the voxColors array by default, or overrideColor if it is available int voxel = (voxelData[i].x + voxelData[i].z * 32 + voxelData[i].y * 32 * 128); //data[voxel] = (colors == null ? voxColors[voxelData[i].color - 1] : colors[voxelData[i].color - 1]); } } return(voxelData); }
/// <summary> /// Load a MagicaVoxel .vox format file into the custom ushort[] structure that we use for voxel chunks. /// </summary> /// <param name="stream">An open BinaryReader stream that is the .vox file.</param> /// <param name="overrideColors">Optional color lookup table for converting RGB values into my internal engine color format.</param> /// <returns>The voxel chunk data for the MagicaVoxel .vox file.</returns> private static Color32[] FromMagica(BinaryReader stream) { // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier string magic = new string(stream.ReadChars(4)); if (magic != "VOX ") return null; int version = stream.ReadInt32(); if (version != 150) { Debug.LogWarning("Vox file version does not match 150. Issues possible."); } // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] data = new Color32[SizeX * SizeY * SizeZ]; Color32[] colors = null; MagicaVoxelData[] voxelData = null; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); int childChunks = stream.ReadInt32(); if (childChunks < 0) { Debug.LogError("childChunks < 0"); return null; } string chunkName = new string(chunkId); switch (chunkName) { // Chunk dimensions case "SIZE": { int sizeX = stream.ReadInt32(); int sizeY = stream.ReadInt32(); int sizeZ = stream.ReadInt32(); if (sizeX > SizeX || sizeZ > SizeZ || sizeY > SizeY) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); break; } // Voxel data case "XYZI": { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); if (numVoxels <= 0) return null; //int div = (subsample ? 2 : 1); // Each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) voxelData[i] = new MagicaVoxelData(stream, subsample); break; } case "RGBA": { colors = new Color32[256]; for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // Convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r,g,b,a); //(ushort) (((r & 0x1f) << 10) | ((g & 0x1f) << 5) | (b & 0x1f)); } break; } default: // Read any excess bytes stream.ReadBytes(chunkSize); break; } } // Failed to read any valid voxel data if (voxelData == null || voxelData.Length == 0) return null; // Push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // Do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].X >= SizeX || voxelData[i].Y >= SizeY || voxelData[i].Z >= SizeZ) continue; // Use the voxColors array by default, or overrideColor if it is available int voxel = (voxelData[i].X + (voxelData[i].Z << LogX) + (voxelData[i].Y << LogY << LogZ)); if (colors == null) { uint col = SVoxColors[voxelData[i].Color - 1]; data[voxel] = new Color32((byte)((col >> 16) & 0xFf), (byte)((col >> 8) & 0xFf), (byte)(col & 0xFf), 0xFf); } else { data[voxel] = colors[voxelData[i].Color - 1]; } } return data; }
public async Task ReadMagica(Stream stream) { int[] colors = null; MagicaVoxelData[] voxelData = null; String magic = new String(ReadChars(stream, 4)); int version = ReadInt32(stream); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic.CompareTo("VOX ") == 0) { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.Position < stream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = ReadChars(stream, 4); int chunkSize = ReadInt32(stream); int childChunks = ReadInt32(stream); String chunkName = new String(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName.CompareTo("SIZE") == 0) { sizex = ReadInt32(stream); sizey = ReadInt32(stream); sizez = ReadInt32(stream); if (sizex > 32 || sizey > 32) { subsample = true; } stream.Seek(chunkSize - 4 * 3, SeekOrigin.Current); } else if (chunkName.CompareTo("XYZI") == 0) { // XYZI contains n voxels int numVoxels = ReadInt32(stream); int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } } else if (chunkName.CompareTo("RGBA") == 0) { colors = new int[256]; for (int i = 0; i < 256; i++) { int r = stream.ReadByte() & 0xff; int g = stream.ReadByte() & 0xff; int b = stream.ReadByte() & 0xff; int a = stream.ReadByte() & 0xff; colors[i] = (a & 0xff) << 24 | (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff); } } else { stream.Seek(chunkSize, SeekOrigin.Current); // read any excess bytes } } if (voxelData.Length == 0) { return; } // now push the voxel data into our voxel chunk structure for (int i = 0; i < voxelData.Length; i++) { // do not store this voxel if it lies out of range of the voxel chunk (32x128x32) if (voxelData[i].x > 31 || voxelData[i].y > 31 || voxelData[i].z > 127) { continue; } int color = 0; if (colors == null) // use default palette { // WTF hardcoded palette is ABGR, doing ABGR => ARGB color = (int)voxColors[voxelData[i].color - 1]; int r = color & 0xff; int g = (color >> 8) & 0xff; int b = (color >> 16) & 0xff; int a = (color >> 28) & 0xff; color = a << 28 | r << 16 | g << 8 | b; } else // use palette from file { color = colors[voxelData[i].color - 1]; } if (timelapse) { await Task.Delay(2); } if (BlockConstructed != null) { Vector3 position = new Vector3(voxelData[i].x, voxelData[i].y, voxelData[i].z); BlockConstructed(new Tuple <Vector3, int>(position, color)); } } } }
private static Bitmap generateWaterMask(int facing, int variant) { setupCurrentColorsH(Color.FromArgb(100, 230, 250)); Bitmap bmp = new Bitmap(vwidth * 16, vheight * 16, PixelFormat.Format32bppArgb); // Bitmap bmp = new Bitmap(4 * 128 + 8, 2 * 128 + 8, PixelFormat.Format32bppArgb); // Specify a pixel format. PixelFormat pxf = PixelFormat.Format32bppArgb; // Lock the bitmap's bits. Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, pxf); // Get the address of the first line. IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap. // int numBytes = bmp.Width * bmp.Height * 3; int numBytes = bmpData.Stride * bmp.Height; byte[] argbValues = new byte[numBytes]; argbValues.Fill <byte>(0); byte[] outlineColors = new byte[numBytes]; outlineColors.Fill <byte>(0); byte[] outlineValues = new byte[numBytes]; outlineValues.Fill <byte>(0); bool[] barePositions = new bool[numBytes]; barePositions.Fill(false); int[] xbuffer = new int[numBytes]; xbuffer.Fill <int>(-999); int[] zbuffer = new int[numBytes]; zbuffer.Fill <int>(-999); for (int mvdx = 15; mvdx >= 0; mvdx--) { for (int mvdy = 0; mvdy <= 15; mvdy++) { MagicaVoxelData vx = new MagicaVoxelData { x = (byte)mvdx, y = (byte)mvdy, z = 0, color = 153 }; int current_color = hcolorcount + 19; //int unshaded = VoxelLogic.WithoutShadingK(vx.color); //int current_color = ((255 - vx.color) % 4 == 0) ? (255 - vx.color) / 4 + hcolorcount : ((254 - vx.color) % 4 == 0) ? (253 - clear) / 4 : (253 - vx.color) / 4; int p = 0; int mod_color = current_color; for (int j = 0; j < vheight; j++) { for (int i = 0; i < 4 * vwidth; i++) { //p = 4 * ((vx.x + vx.y) * 2 + 2) + i + bmpData.Stride * (128 + 2 - vx.y + vx.x + j); mod_color = current_color; p = voxelToPixelH16(i, j, vx.x, vx.y, 0, current_color, bmpData.Stride, 0, true); if (argbValues[p] == 0) { zbuffer[p] = vx.z; xbuffer[p] = vx.x; if (i % 4 == 3) { double wave = Simplex.FindNoiseFlatWater(facing, vx.x, vx.y, variant); if (wave > 0.73) { wave = 85 * wave; } else if (wave > 0.64) { wave = 65 * wave; } else if (wave > 0.55) { wave = 50 * wave; } else if (wave < 0.45) { wave += 0.2; if (wave < 0.5) { wave = -15 / wave; mod_color -= hcolorcount; } else if (wave < 0.55) { wave = -11 / wave; mod_color -= hcolorcount; } else if (wave < 0.6) { wave = -7 / wave; mod_color--; } else { wave = 6.0 * (wave - 0.25); } } else { wave = 32.0 * wave; } wave = Clamp(wave, -72.0, 72.0); mod_color = (byte)(((int)(wave / 12.2)) * 2 + mod_color); argbValues[p - 3] = hrendered[mod_color][i - 3 + j * (vwidth * 4)]; argbValues[p - 2] = hrendered[mod_color][i - 2 + j * (vwidth * 4)]; argbValues[p - 1] = hrendered[mod_color][i - 1 + j * (vwidth * 4)]; argbValues[p - 0] = 255; if (outlineColors[p] == 0) { outlineColors[p] = hrendered[mod_color][i + (4 * vwidth * vheight)]; } } } } } } } /* * bool darkOutline = false; * for (int i = 3; i < numBytes; i += 4) * { * if (argbValues[i] > 255 * waver_alpha && barePositions[i] == false) * { * * if (i + 4 >= 0 && i + 4 < argbValues.Length && argbValues[i + 4] == 0 && darkOutline && outlineValues[i + 4] == 0) { outlineValues[i + 4] = 255; } else if (i + 4 >= 0 && i + 4 < argbValues.Length && barePositions[i + 4] == false && (zbuffer[i] - 1 > zbuffer[i + 4] || xbuffer[i] - 1 > xbuffer[i + 4]) && outlineValues[i + 4] == 0) { outlineValues[i + 4] = 255; outlineValues[i + 4 - 1] = outlineColors[i - 1]; outlineValues[i + 4 - 2] = outlineColors[i - 2]; outlineValues[i + 4 - 3] = outlineColors[i - 3]; } * if (i - 4 >= 0 && i - 4 < argbValues.Length && argbValues[i - 4] == 0 && darkOutline && outlineValues[i - 4] == 0) { outlineValues[i - 4] = 255; } else if (i - 4 >= 0 && i - 4 < argbValues.Length && barePositions[i - 4] == false && (zbuffer[i] - 1 > zbuffer[i - 4] || xbuffer[i] - 1 > xbuffer[i - 4]) && outlineValues[i - 4] == 0) { outlineValues[i - 4] = 255; outlineValues[i - 4 - 1] = outlineColors[i - 1]; outlineValues[i - 4 - 2] = outlineColors[i - 2]; outlineValues[i - 4 - 3] = outlineColors[i - 3]; } * if (i + bmpData.Stride >= 0 && i + bmpData.Stride < argbValues.Length && argbValues[i + bmpData.Stride] == 0 && darkOutline && outlineValues[i + bmpData.Stride] == 0) { outlineValues[i + bmpData.Stride] = 255; } else if (i + bmpData.Stride >= 0 && i + bmpData.Stride < argbValues.Length && barePositions[i + bmpData.Stride] == false && (zbuffer[i] - 1 > zbuffer[i + bmpData.Stride] || xbuffer[i] - 1 > xbuffer[i + bmpData.Stride]) && outlineValues[i + bmpData.Stride] == 0) { outlineValues[i + bmpData.Stride] = 255; outlineValues[i + bmpData.Stride - 1] = outlineColors[i - 1]; outlineValues[i + bmpData.Stride - 2] = outlineColors[i - 2]; outlineValues[i + bmpData.Stride - 3] = outlineColors[i - 3]; } * if (i - bmpData.Stride >= 0 && i - bmpData.Stride < argbValues.Length && argbValues[i - bmpData.Stride] == 0 && darkOutline && outlineValues[i - bmpData.Stride] == 0) { outlineValues[i - bmpData.Stride] = 255; } else if (i - bmpData.Stride >= 0 && i - bmpData.Stride < argbValues.Length && barePositions[i - bmpData.Stride] == false && (zbuffer[i] - 1 > zbuffer[i - bmpData.Stride] || xbuffer[i] - 1 > xbuffer[i - bmpData.Stride]) && outlineValues[i - bmpData.Stride] == 0) { outlineValues[i - bmpData.Stride] = 255; outlineValues[i - bmpData.Stride - 1] = outlineColors[i - 1]; outlineValues[i - bmpData.Stride - 2] = outlineColors[i - 2]; outlineValues[i - bmpData.Stride - 3] = outlineColors[i - 3]; } * } * * } */ for (int i = 3; i < numBytes; i += 4) { if (argbValues[i] > 0) { argbValues[i] = 255; } if (outlineValues[i] == 255) { argbValues[i] = 255; argbValues[i - 1] = outlineValues[i - 1]; argbValues[i - 2] = outlineValues[i - 2]; argbValues[i - 3] = outlineValues[i - 3]; } } Marshal.Copy(argbValues, 0, ptr, numBytes); // Unlock the bits. bmp.UnlockBits(bmpData); return(bmp); }
//////loading magica voxel////////////// public void loadFromFile(string fileName) { //using (BinaryReader stream = new BinaryReader(new FileStream(Application.dataPath + "/StreamingAssets/"+fileName, FileMode.Open))) TextAsset asset = Resources.Load(fileName) as TextAsset; Stream s = new MemoryStream(asset.bytes); //BinaryReader br = new BinaryReader(s); using (BinaryReader stream = new BinaryReader(s)) { MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); //int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { int width = 0, height = 0, depth = 0; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); //int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { width = stream.ReadInt32(); depth = stream.ReadInt32(); height = stream.ReadInt32(); //if (width > 32 || height > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) { voxelData[i] = new MagicaVoxelData(stream, subsample); } } else if (chunkName == "RGBA") { for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r, g, b, a); } } else { stream.ReadBytes(chunkSize); // read any excess bytes } } if (voxelData.Length == 0) { return; // failed to read any valid voxel data } // sizes this.width = width; this.height = height; this.depth = depth; foreach (MagicaVoxelData v in voxelData) { try { voxels.Add(new Voxel(v.x, v.z, v.y, (byte)(v.color - 1))); } catch (Exception) { // Console.WriteLine(e); //Debug.Log(v.x + " " + v.y + " " + v.z); } } } } }
private static void FromMagica(BinaryReader stream, string volumeName, float voxelSize, bool centerPivot) { // check out http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=Home for the file format used below // we're going to return a voxel chunk worth of data Color32[] colors = new Color32[256]; for (int i = 1; i < 256; i++) { uint hexval = defaultColors[i]; byte cb = (byte)((hexval >> 16) & 0xFF); byte cg = (byte)((hexval >> 8) & 0xFF); byte cr = (byte)((hexval >> 0) & 0xFF); colors[i - 1] = new Color32(cr, cg, cb, 255); } MagicaVoxelData[] voxelData = null; string magic = new string(stream.ReadChars(4)); //int version = stream.ReadInt32(); // a MagicaVoxel .vox file starts with a 'magic' 4 character 'VOX ' identifier if (magic == "VOX ") { int sizex = 0, sizey = 0, sizez = 0; bool subsample = false; while (stream.BaseStream.Position < stream.BaseStream.Length) { // each chunk has an ID, size and child chunks char[] chunkId = stream.ReadChars(4); int chunkSize = stream.ReadInt32(); //int childChunks = stream.ReadInt32(); string chunkName = new string(chunkId); // there are only 2 chunks we only care about, and they are SIZE and XYZI if (chunkName == "SIZE") { sizex = stream.ReadInt32(); sizez = stream.ReadInt32(); sizey = stream.ReadInt32(); //if (sizex > 32 || sizey > 32) subsample = true; stream.ReadBytes(chunkSize - 4 * 3); } else if (chunkName == "XYZI") { // XYZI contains n voxels int numVoxels = stream.ReadInt32(); // int div = (subsample ? 2 : 1); // each voxel has x, y, z and color index values voxelData = new MagicaVoxelData[numVoxels]; for (int i = 0; i < voxelData.Length; i++) voxelData[i] = new MagicaVoxelData(stream, subsample); } else if (chunkName == "RGBA") { for (int i = 0; i < 256; i++) { byte r = stream.ReadByte(); byte g = stream.ReadByte(); byte b = stream.ReadByte(); byte a = stream.ReadByte(); // convert RGBA to our custom voxel format (16 bits, 0RRR RRGG GGGB BBBB) colors[i] = new Color32(r, g, b, a); } } else stream.ReadBytes(chunkSize); // read any excess bytes } if (voxelData.Length == 0) return; // failed to read any valid voxel data // Quick and dirty multi-part splitter if size > 32 on any axis //if (sizex > MAX_VOLUME_DIMENSION || sizey > MAX_VOLUME_DIMENSION || sizez > MAX_VOLUME_DIMENSION) //{ // var parentObject = new GameObject(); // parentObject.name = volumeName; // int xparts = (sizex/MAX_VOLUME_DIMENSION) + (sizex%MAX_VOLUME_DIMENSION > 0 ? 1 : 0); // int yparts = (sizey/MAX_VOLUME_DIMENSION) + (sizey%MAX_VOLUME_DIMENSION > 0 ? 1 : 0); // int zparts = (sizez/MAX_VOLUME_DIMENSION) + (sizez%MAX_VOLUME_DIMENSION > 0 ? 1 : 0); // int xRem = sizex % MAX_VOLUME_DIMENSION; // int yRem = sizey % MAX_VOLUME_DIMENSION; // int zRem = sizez % MAX_VOLUME_DIMENSION; // int totalX = xRem > 0 ? ((xparts - 1) * MAX_VOLUME_DIMENSION) + xRem : xparts * MAX_VOLUME_DIMENSION; // int totalY = yRem > 0 ? ((yparts - 1) * MAX_VOLUME_DIMENSION) + yRem : yparts * MAX_VOLUME_DIMENSION; // int totalZ = zRem > 0 ? ((zparts - 1) * MAX_VOLUME_DIMENSION) + zRem : zparts * MAX_VOLUME_DIMENSION; // Volume[,,] volumeRefs = new Volume[xparts,yparts,zparts]; // for (int x = 0; x < xparts; x++) // for (int y = 0; y < yparts; y++) // for (int z = 0; z < zparts; z++) // { // var newObject = // Editor.Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as // GameObject; // if (newObject != null) // { // newObject.name = volumeName + " (" + x + "," + y + "," + z + ")"; // newObject.GetComponent<Volume>().Material = EditorUtility.PicaVoxelDiffuseMaterial; // newObject.GetComponent<Volume>().VoxelSize = voxelSize; // newObject.GetComponent<Volume>().GenerateBasic(FillMode.None); // newObject.transform.parent = parentObject.transform; // Volume voxelVolume = newObject.GetComponent<Volume>(); // voxelVolume.XSize = x < xparts - 1 ? MAX_VOLUME_DIMENSION : xRem; // voxelVolume.YSize = y < yparts - 1 ? MAX_VOLUME_DIMENSION : yRem; // voxelVolume.ZSize = z < zparts - 1 ? MAX_VOLUME_DIMENSION : zRem; // voxelVolume.Frames[0].XSize = voxelVolume.XSize; // voxelVolume.Frames[0].YSize = voxelVolume.YSize; // voxelVolume.Frames[0].ZSize = voxelVolume.ZSize; // voxelVolume.Frames[0].Voxels = new Voxel[voxelVolume.XSize* voxelVolume.YSize* voxelVolume.ZSize]; // newObject.transform.parent = parentObject.transform; // if (!centerPivot) // newObject.transform.localPosition = new Vector3(x * MAX_VOLUME_DIMENSION * voxelSize, y * MAX_VOLUME_DIMENSION * voxelSize, z * MAX_VOLUME_DIMENSION * voxelSize); // else // { // newObject.GetComponent<Volume>().Pivot = (new Vector3(MAX_VOLUME_DIMENSION, MAX_VOLUME_DIMENSION, MAX_VOLUME_DIMENSION) * voxelSize) / 2f; // newObject.GetComponent<Volume>().UpdatePivot(); // newObject.transform.localPosition = -(new Vector3(totalX * (voxelSize / 2f), totalY * (voxelSize / 2f), totalZ * (voxelSize / 2f))) // + new Vector3(MAX_VOLUME_DIMENSION * (voxelSize / 2f), MAX_VOLUME_DIMENSION * (voxelSize / 2f), MAX_VOLUME_DIMENSION * (voxelSize / 2f)) // + new Vector3(x * MAX_VOLUME_DIMENSION * voxelSize, y * MAX_VOLUME_DIMENSION * voxelSize, z * MAX_VOLUME_DIMENSION * voxelSize); // } // volumeRefs[x, y, z] = voxelVolume; // } // } // foreach (MagicaVoxelData v in voxelData) // { // try // { // int xpart = v.x / MAX_VOLUME_DIMENSION; // int ypart = v.z / MAX_VOLUME_DIMENSION; // int zpart = v.y / MAX_VOLUME_DIMENSION; // volumeRefs[xpart, ypart, zpart].Frames[0].Voxels[(v.x - (MAX_VOLUME_DIMENSION * xpart)) + volumeRefs[xpart, ypart, zpart].XSize * ((v.z - (MAX_VOLUME_DIMENSION * ypart)) + volumeRefs[xpart, ypart, zpart].YSize * (v.y - (MAX_VOLUME_DIMENSION * zpart)))] = new Voxel() // { // Active = true, // Color = colors[v.color - 1], // Value = 128 // }; // } // catch (Exception) // { // Debug.Log(v.x + " " + v.y + " " + v.z); // } // } // foreach (Volume v in volumeRefs) // { // v.CreateChunks(); // v.SaveForSerialize(); // } //} //else //{ // Single volume var newObject = Editor.Instantiate(EditorUtility.VoxelVolumePrefab, Vector3.zero, Quaternion.identity) as GameObject; if (newObject != null) { newObject.name = volumeName; newObject.GetComponent<Volume>().Material = EditorUtility.PicaVoxelDiffuseMaterial; newObject.GetComponent<Volume>().GenerateBasic(FillMode.None); Volume voxelVolume = newObject.GetComponent<Volume>(); voxelVolume.XSize = sizex; voxelVolume.YSize = sizey; voxelVolume.ZSize = sizez; voxelVolume.Frames[0].XSize = sizex; voxelVolume.Frames[0].YSize = sizey; voxelVolume.Frames[0].ZSize = sizez; voxelVolume.Frames[0].Voxels = new Voxel[sizex * sizey * sizez]; voxelVolume.VoxelSize = voxelSize; if (centerPivot) { voxelVolume.Pivot = (new Vector3(voxelVolume.XSize, voxelVolume.YSize, voxelVolume.ZSize) * voxelVolume.VoxelSize) / 2f; voxelVolume.UpdatePivot(); } foreach (MagicaVoxelData v in voxelData) { try { voxelVolume.Frames[0].Voxels[v.x + sizex * (v.z + sizey * v.y)] = new Voxel() { Active = true, Color = colors[v.color-1], Value = 128 }; } catch (Exception) { Debug.Log(v.x + " " + v.y + " " + v.z); } } voxelVolume.CreateChunks(); voxelVolume.SaveForSerialize(); } // } } }