namespace MagicaVoxelToolbox { using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using System.Text; public static class VoxelFile { #region --- SUB --- public delegate void OnProgressHandler (float progress); #endregion #region --- API --- public static VoxelData GetVoxelData (byte[] voxelBytes, bool isVox, OnProgressHandler onProgress = null) { return isVox ? GetVoxelDataFromVox(voxelBytes, onProgress) : GetVoxelDataFromQb(voxelBytes); } public static byte[] GetVoxelByte (VoxelData data, bool isVox, OnProgressHandler onProgress = null) { return isVox ? GetVoxFromVoxelData(data, onProgress) : GetQbFromVoxelData(data); } #endregion #region --- VOX --- #region --- Read --- private static VoxelData GetVoxelDataFromVox (byte[] voxBytes, OnProgressHandler onProgress) { VoxelData data = new VoxelData(); if (!CheckID(voxBytes, "VOX ")) { Debug.LogError("Error with Magic Number. The file is not a vox file."); return null; } using (MemoryStream ms = new MemoryStream(voxBytes)) { using (BinaryReader br = new BinaryReader(ms)) { // VOX_ br.ReadInt32(); // VERSION data.Version = System.BitConverter.ToInt32(br.ReadBytes(4), 0); // MAIN byte[] chunkId = br.ReadBytes(4); int mainChunkSize = br.ReadInt32(); int mainChildrenSize = br.ReadInt32(); br.ReadBytes(mainChunkSize); if (!CheckID(chunkId, "MAIN")) { Debug.LogError("Error with Main Chunk ID"); return null; } // Containt int readSize = 0; Vector3 tempSize = new Vector3(); while (readSize < mainChildrenSize) { string id = GetID(br.ReadBytes(4)); readSize += 4; switch (id) { case "PACK": readSize += ReadPackChunk(br); break; case "SIZE": readSize += ReadSizeChunk(br, out tempSize); break; case "XYZI": int[,,] tempVoxels = new int[(int)tempSize.x, (int)tempSize.y, (int)tempSize.z]; readSize += ReadVoxelChunk(br, ref tempVoxels); data.Voxels.Add(tempVoxels); break; case "RGBA": readSize += ReadPalattee(br, ref data.Palette); break; case "nTRN": readSize += ReadTransform(br, ref data); break; case "nGRP": readSize += ReadGroup(br, ref data); break; case "nSHP": readSize += ReadShape(br, ref data); break; case "MATL": readSize += ReadMaterial(br, ref data); break; case "RIGG": readSize += ReadRig(br, ref data, 0); break; case "_RIG": readSize += ReadRig(br, ref data, VoxelData.RigData.CURRENT_VERSION); break; default: int chunkSize = br.ReadInt32(); int childrenSize = br.ReadInt32(); br.ReadBytes(chunkSize + childrenSize); readSize += chunkSize + childrenSize + 4 + 4; break; } } if (onProgress != null) { onProgress.Invoke((float)readSize / mainChildrenSize); } // Add Default Node if No Node if (data.Transforms.Count == 0) { data.ResetToDefaultNode(); } // Mat Fix if (data.Materials != null) { data.Materials.Insert(0, new VoxelData.MaterialData()); } } } return data; } // Chunk Reader private static int ReadPackChunk (BinaryReader _br) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); _br.ReadInt32(); if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadSizeChunk (BinaryReader _br, out Vector3 size) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int x = _br.ReadInt32(); int z = _br.ReadInt32(); int y = _br.ReadInt32(); size = new Vector3(x, y, z); if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadVoxelChunk (BinaryReader _br, ref int[,,] tempVoxels) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int voxelNum = _br.ReadInt32(); for (int i = 0; i < voxelNum; ++i) { int x = _br.ReadByte(); int z = _br.ReadByte(); int y = _br.ReadByte(); tempVoxels[x, y, z] = _br.ReadByte(); } if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadPalattee (BinaryReader _br, ref List colors) { colors = new List(); int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); for (int i = 0; i < 256; i++) { colors.Add(new Color( _br.ReadByte() / 255f, _br.ReadByte() / 255f, _br.ReadByte() / 255f, _br.ReadByte() / 255f) ); } if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadMaterial (BinaryReader _br, ref VoxelData data) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int id = _br.ReadInt32(); var dic = ReadDictionary(_br); data.Materials.Add(new VoxelData.MaterialData() { Index = id, Type = VoxelData.MaterialData.GetTypeFromString(TryGetString(dic, "_type", "_diffuse")), Weight = TryGetFloat(dic, "_weight", 0f), Rough = TryGetFloat(dic, "_rough", 0f), Spec = TryGetFloat(dic, "_spec", 0f), Ior = TryGetFloat(dic, "_ior", 0f), Att = TryGetFloat(dic, "_att", 0f), Flux = TryGetFloat(dic, "_flux", 0f), LDR = TryGetFloat(dic, "_ldr", 0f), Plastic = TryGetInt(dic, "_plastic", 0), }); if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadTransform (BinaryReader _br, ref VoxelData data) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int id = _br.ReadInt32(); var dic = ReadDictionary(_br); int childID = _br.ReadInt32(); int reservedID = _br.ReadInt32(); int layerID = _br.ReadInt32(); int frameNum = _br.ReadInt32(); var frameData = new VoxelData.TransformData.FrameData[frameNum]; for (int i = 0; i < frameNum; i++) { var frameDic = ReadDictionary(_br); Vector3 rot; Vector3 scale; VoxMatrixByteToTransform(TryGetByte(frameDic, "_r", 4), out rot, out scale); frameData[i] = new VoxelData.TransformData.FrameData() { Position = TryGetVector3(frameDic, "_t", Vector3.zero), Rotation = rot, Scale = scale, }; // Fix Y-Z frameData[i].Position = frameData[i].Position; frameData[i].Scale = frameData[i].Scale; } if (!data.Transforms.ContainsKey(id)) { data.Transforms.Add(id, new VoxelData.TransformData() { Name = TryGetString(dic, "_name", ""), Hidden = TryGetString(dic, "_hidden", "0") == "1", ChildID = childID, LayerID = layerID, Reserved = reservedID, Frames = frameData, }); } if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadGroup (BinaryReader _br, ref VoxelData data) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int id = _br.ReadInt32(); var nodeAttr = ReadDictionary(_br); int childNum = _br.ReadInt32(); var childData = new int[childNum]; for (int i = 0; i < childNum; i++) { childData[i] = _br.ReadInt32(); } if (!data.Groups.ContainsKey(id)) { data.Groups.Add(id, new VoxelData.GroupData() { Attributes = nodeAttr, ChildNodeId = childData, }); } if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadShape (BinaryReader _br, ref VoxelData data) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int id = _br.ReadInt32(); var nodeAttr = ReadDictionary(_br); int modelNum = _br.ReadInt32(); var modelData = new KeyValuePair>[modelNum]; for (int i = 0; i < modelNum; i++) { int modelId = _br.ReadInt32(); var modelAttr = ReadDictionary(_br); modelData[i] = new KeyValuePair>(modelId, modelAttr); } if (!data.Shapes.ContainsKey(id)) { data.Shapes.Add(id, new VoxelData.ShapeData() { Attributes = nodeAttr, ModelData = modelData, }); } if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } private static int ReadRig (BinaryReader _br, ref VoxelData data, int version) { int chunkSize = _br.ReadInt32(); int childrenSize = _br.ReadInt32(); int id = _br.ReadInt32(); var rigData = new VoxelData.RigData() { Bones = new List(), Weights = new List(), Version = version, }; // Bone int boneCount = _br.ReadInt32(); for (int i = 0; i < boneCount; i++) { var bone = new VoxelData.RigData.Bone { Name = ReadString(_br), ParentIndex = _br.ReadInt32(), PositionX = _br.ReadInt32(), PositionY = _br.ReadInt32(), PositionZ = _br.ReadInt32(), }; rigData.Bones.Add(bone); } for (int i = 0; i < rigData.Bones.Count; i++) { int pIndex = rigData.Bones[i].ParentIndex; if (pIndex >= 0 && pIndex < rigData.Bones.Count) { rigData.Bones[i].Parent = rigData.Bones[pIndex]; } } // Weight int WeightCount = _br.ReadInt32(); for (int i = 0; i < WeightCount; i++) { var weight = new VoxelData.RigData.Weight { X = _br.ReadInt32(), Y = _br.ReadInt32(), Z = _br.ReadInt32(), BoneIndexA = _br.ReadInt32(), BoneIndexB = _br.ReadInt32(), }; rigData.Weights.Add(weight); } // Version rigData.FixVersion(); // End if (!data.Rigs.ContainsKey(id)) { data.Rigs.Add(id, rigData); } if (childrenSize > 0) { _br.ReadBytes(childrenSize); } return chunkSize + childrenSize + 4 + 4; } #endregion #region --- Write --- private static byte[] GetVoxFromVoxelData (VoxelData data, OnProgressHandler onProgress) { if (!data) { return null; } List voxByte = new List(); byte[] mainChrunk = WriteMain(data, onProgress); voxByte.AddRange(Encoding.Default.GetBytes("VOX ")); voxByte.AddRange(GetBytes(data.Version)); voxByte.AddRange(Encoding.Default.GetBytes("MAIN")); voxByte.AddRange(GetBytes(0)); voxByte.AddRange(GetBytes(mainChrunk.Length)); voxByte.AddRange(mainChrunk); return voxByte.ToArray(); } private static byte[] WriteMain (VoxelData data, OnProgressHandler onProgress) { const float STEP_COUNT = 5f; List bytes = new List(); if (data.Voxels.Count > 1) { // PACK //bytes.AddRange(WritePack(data)); } for (int i = 0; i < data.Voxels.Count; i++) { if (onProgress != null) { onProgress.Invoke((i + 1) / STEP_COUNT / data.Voxels.Count); } // SIZE bytes.AddRange(WriteSize(data.Voxels[i])); // XYZI bytes.AddRange(WriteVoxels(data.Voxels[i])); } // RGBA if (onProgress != null) { onProgress.Invoke((2 / STEP_COUNT)); } bytes.AddRange(WritePalette(data.Palette)); // TGS var tgsList = new SortedList(); if (onProgress != null) { onProgress.Invoke(3 / STEP_COUNT); } // nTRN foreach (var t in data.Transforms) { tgsList.Add(t.Key, WriteTransform(t.Key, t.Value)); } // nGRP foreach (var g in data.Groups) { tgsList.Add(g.Key, WriteGroup(g.Key, g.Value)); } // nSHP foreach (var s in data.Shapes) { tgsList.Add(s.Key, WriteShape(s.Key, s.Value)); } for (int i = 0; i < tgsList.Keys.Count; i++) { bytes.AddRange(tgsList[tgsList.Keys[i]]); } if (onProgress != null) { onProgress.Invoke(4 / STEP_COUNT); } // MATL for (int i = 0; i < data.Materials.Count; i++) { bytes.AddRange(WriteMaterial(data.Materials[i])); } if (onProgress != null) { onProgress.Invoke(5 / STEP_COUNT); } // RIGG foreach (var r in data.Rigs) { bytes.AddRange(WriteRig(r.Key, r.Value)); } return bytes.ToArray(); } // Chrunk Writer private static byte[] WritePack (VoxelData data) { List bytes = new List(); bytes.AddRange(GetBytes(data.Voxels.Count)); return ToChrunkByte(bytes, "PACK"); } private static byte[] WriteSize (int[,,] voxels) { List bytes = new List(); int size0 = Mathf.Clamp(voxels.GetLength(0), byte.MinValue, byte.MaxValue); int size1 = Mathf.Clamp(voxels.GetLength(1), byte.MinValue, byte.MaxValue); int size2 = Mathf.Clamp(voxels.GetLength(2), byte.MinValue, byte.MaxValue); bytes.AddRange(GetBytes(size0)); bytes.AddRange(GetBytes(size2)); bytes.AddRange(GetBytes(size1)); return ToChrunkByte(bytes, "SIZE"); } private static byte[] WriteVoxels (int[,,] voxels) { List bytes = new List(); int lenX = Mathf.Clamp(voxels.GetLength(0), byte.MinValue, byte.MaxValue); int lenY = Mathf.Clamp(voxels.GetLength(1), byte.MinValue, byte.MaxValue); int lenZ = Mathf.Clamp(voxels.GetLength(2), byte.MinValue, byte.MaxValue); int voxelNum = 0; for (byte x = 0; x < lenX; x++) { for (byte y = 0; y < lenY; y++) { for (byte z = 0; z < lenZ; z++) { if (voxels[x, y, z] != 0) { bytes.Add(x); bytes.Add(z); bytes.Add(y); bytes.Add((byte)voxels[x, y, z]); voxelNum++; } } } } bytes.InsertRange(0, GetBytes(voxelNum)); return ToChrunkByte(bytes, "XYZI"); } private static byte[] WritePalette (List palette) { List bytes = new List(); for (int i = 0; i < 256; i++) { Color color = i < palette.Count ? palette[i] : Color.black; bytes.Add((byte)(color.r * 255f)); bytes.Add((byte)(color.g * 255f)); bytes.Add((byte)(color.b * 255f)); bytes.Add((byte)(color.a * 255f)); } return ToChrunkByte(bytes, "RGBA"); } private static byte[] WriteTransform (int id, VoxelData.TransformData transform) { List bytes = new List(); bytes.AddRange(GetBytes(id)); // Dic Name Hidden bytes.AddRange(GetBytes(2)); AddVoxStringBytes(ref bytes, "_name"); AddVoxStringBytes(ref bytes, transform.Name); AddVoxStringBytes(ref bytes, "_hidden"); AddVoxStringBytes(ref bytes, transform.Hidden ? "1" : "0"); // child node id bytes.AddRange(GetBytes(transform.ChildID)); bytes.AddRange(GetBytes(transform.Reserved)); bytes.AddRange(GetBytes(transform.LayerID)); bytes.AddRange(GetBytes(transform.Frames.Length)); // frame dic for (int i = 0; i < transform.Frames.Length; i++) { var frame = transform.Frames[i]; bytes.AddRange(GetBytes(2)); AddVoxStringBytes(ref bytes, "_r"); AddVoxStringBytes(ref bytes, TransformToVoxMatrixByteString(frame.Rotation, frame.Scale)); AddVoxStringBytes(ref bytes, "_t"); AddVoxStringBytes(ref bytes, string.Format( "{0} {1} {2}", ((int)frame.Position.x).ToString(), ((int)frame.Position.z).ToString(), ((int)frame.Position.y).ToString() )); } return ToChrunkByte(bytes, "nTRN"); } private static byte[] WriteGroup (int id, VoxelData.GroupData group) { List bytes = new List(); bytes.AddRange(GetBytes(id)); bytes.AddRange(GetBytes(group.Attributes.Count)); foreach (var att in group.Attributes) { AddVoxStringBytes(ref bytes, att.Key); AddVoxStringBytes(ref bytes, att.Value); } bytes.AddRange(GetBytes(group.ChildNodeId.Length)); for (int i = 0; i < group.ChildNodeId.Length; i++) { bytes.AddRange(GetBytes(group.ChildNodeId[i])); } return ToChrunkByte(bytes, "nGRP"); } private static byte[] WriteShape (int id, VoxelData.ShapeData shape) { List bytes = new List(); bytes.AddRange(GetBytes(id)); bytes.AddRange(GetBytes(shape.Attributes.Count)); foreach (var att in shape.Attributes) { AddVoxStringBytes(ref bytes, att.Key); AddVoxStringBytes(ref bytes, att.Value); } bytes.AddRange(GetBytes(shape.ModelData.Length)); for (int i = 0; i < shape.ModelData.Length; i++) { var pair = shape.ModelData[i]; bytes.AddRange(GetBytes(pair.Key)); bytes.AddRange(GetBytes(pair.Value.Count)); foreach (var att in pair.Value) { AddVoxStringBytes(ref bytes, att.Key); AddVoxStringBytes(ref bytes, att.Value); } } return ToChrunkByte(bytes, "nSHP"); } private static byte[] WriteMaterial (VoxelData.MaterialData material) { List bytes = new List(); bytes.AddRange(GetBytes(material.Index)); bytes.AddRange(GetBytes(9)); AddVoxStringBytes(ref bytes, "_type"); AddVoxStringBytes(ref bytes, VoxelData.MaterialData.GetStringFromType(material.Type)); AddVoxStringBytes(ref bytes, "_weight"); AddVoxStringBytes(ref bytes, material.Weight.ToString()); AddVoxStringBytes(ref bytes, "_rough"); AddVoxStringBytes(ref bytes, material.Rough.ToString()); AddVoxStringBytes(ref bytes, "_spec"); AddVoxStringBytes(ref bytes, material.Spec.ToString()); AddVoxStringBytes(ref bytes, "_ior"); AddVoxStringBytes(ref bytes, material.Ior.ToString()); AddVoxStringBytes(ref bytes, "_att"); AddVoxStringBytes(ref bytes, material.Att.ToString()); AddVoxStringBytes(ref bytes, "_flux"); AddVoxStringBytes(ref bytes, material.Flux.ToString()); AddVoxStringBytes(ref bytes, "_ldr"); AddVoxStringBytes(ref bytes, material.LDR.ToString()); AddVoxStringBytes(ref bytes, "_plastic"); AddVoxStringBytes(ref bytes, material.Plastic.ToString()); return ToChrunkByte(bytes, "MATL"); } private static byte[] WriteRig (int id, VoxelData.RigData rig) { List bytes = new List(); bytes.AddRange(GetBytes(id)); // Bones bytes.AddRange(GetBytes(rig.Bones.Count)); for (int i = 0; i < rig.Bones.Count; i++) { var bone = rig.Bones[i]; AddVoxStringBytes(ref bytes, bone.Name); bytes.AddRange(GetBytes(bone.ParentIndex)); bytes.AddRange(GetBytes(bone.PositionX)); bytes.AddRange(GetBytes(bone.PositionY)); bytes.AddRange(GetBytes(bone.PositionZ)); } // Weights bytes.AddRange(GetBytes(rig.Weights.Count)); for (int i = 0; i < rig.Weights.Count; i++) { var weight = rig.Weights[i]; bytes.AddRange(GetBytes(weight.X)); bytes.AddRange(GetBytes(weight.Y)); bytes.AddRange(GetBytes(weight.Z)); bytes.AddRange(GetBytes(weight.BoneIndexA)); bytes.AddRange(GetBytes(weight.BoneIndexB)); } return ToChrunkByte(bytes, "_RIG"); } #endregion #endregion #region --- QB --- private static VoxelData GetVoxelDataFromQb (byte[] qbBytes) { QbData qData = new QbData(); using (MemoryStream ms = new MemoryStream(qbBytes)) { using (BinaryReader br = new BinaryReader(ms)) { int index; int data; uint count; const uint CODEFLAG = 2; const uint NEXTSLICEFLAG = 6; qData.Version = br.ReadUInt32(); qData.ColorFormat = br.ReadUInt32(); qData.ZAxisOrientation = br.ReadUInt32(); qData.Compressed = br.ReadUInt32(); qData.VisibleMask = br.ReadUInt32(); qData.NumMatrixes = br.ReadUInt32(); qData.MatrixList = new List(); for (int i = 0; i < qData.NumMatrixes; i++) { QbData.QbMatrix qm = new QbData.QbMatrix(); // read matrix name int nameLength = br.ReadByte(); qm.Name = br.ReadChars(nameLength).ToString(); // Name // read matrix size qm.SizeX = br.ReadInt32(); qm.SizeY = br.ReadInt32(); qm.SizeZ = br.ReadInt32(); // read matrix position qm.PosX = br.ReadInt32(); qm.PosY = br.ReadInt32(); qm.PosZ = br.ReadInt32(); // create matrix and add to matrix list qm.Voxels = new int[qm.SizeX, qm.SizeY, qm.SizeZ]; int x, y, z; if (qData.Compressed == 0) { for (z = 0; z < qm.SizeZ; z++) { for (y = 0; y < qm.SizeY; y++) { for (x = 0; x < qm.SizeX; x++) { qm.Voxels[x, y, z] = (int)br.ReadUInt32(); } } } } else { z = 0; while (z < qm.SizeZ) { index = 0; while (true) { data = (int)br.ReadUInt32(); if (data == NEXTSLICEFLAG) break; else if (data == CODEFLAG) { count = br.ReadUInt32(); data = (int)br.ReadUInt32(); for (int j = 0; j < count; j++) { x = index % qm.SizeX; y = index / qm.SizeX; index++; qm.Voxels[x, y, z] = data; } } else { x = index % qm.SizeX; y = index / qm.SizeX; index++; qm.Voxels[x, y, z] = data; } } z++; } } qData.MatrixList.Add(qm); } } } return qData.GetVoxelData(); } private static byte[] GetQbFromVoxelData (VoxelData data) { List bytes = new List(); bytes.AddRange(System.BitConverter.GetBytes((uint)257)); bytes.AddRange(System.BitConverter.GetBytes((uint)0)); // Always RGBA bytes.AddRange(System.BitConverter.GetBytes((uint)1)); // Always Right Handed bytes.AddRange(System.BitConverter.GetBytes(0)); // Always Not Compressed bytes.AddRange(System.BitConverter.GetBytes((uint)1)); bytes.AddRange(System.BitConverter.GetBytes((uint)data.Voxels.Count)); for (int index = 0; index < data.Voxels.Count; index++) { var voxels = data.Voxels[index]; // Get Size int sizeX = voxels.GetLength(0); int sizeY = voxels.GetLength(1); int sizeZ = voxels.GetLength(2); // Get Position Vector3 size = data.GetModelSize(index); Vector3 pos, rot, scl; data.GetModelTransform(index, out pos, out rot, out scl); int posX = (int)pos.x - (int)size.x / 2; int posY = (int)pos.y - (int)size.y / 2; int posZ = (int)pos.z - (int)size.z / 2; // name bytes.Add(0); // size bytes.AddRange(System.BitConverter.GetBytes(sizeX)); bytes.AddRange(System.BitConverter.GetBytes(sizeY)); bytes.AddRange(System.BitConverter.GetBytes(sizeZ)); // pos bytes.AddRange(System.BitConverter.GetBytes(posX)); bytes.AddRange(System.BitConverter.GetBytes(posY)); bytes.AddRange(System.BitConverter.GetBytes(posZ)); // voxels for (int z = 0; z < sizeZ; z++) { for (int y = 0; y < sizeY; y++) { for (int x = 0; x < sizeX; x++) { int v = voxels[x, y, z]; bytes.AddRange(System.BitConverter.GetBytes( v == 0 ? 0 : ColorToInt(data.GetColorFromPalette(v)) )); } } } } return bytes.ToArray(); } #endregion #region --- UTL --- private static byte[] GetBytes (int i) { return System.BitConverter.GetBytes(i); } private static void AddVoxStringBytes (ref List bytes, string str) { var strBytes = Encoding.Default.GetBytes(str); bytes.AddRange(GetBytes(strBytes.Length)); bytes.AddRange(strBytes); } private static bool CheckID (byte[] bytes, string id) { for (int i = 0; i < bytes.Length && i < id.Length; i++) { if (id[i] != bytes[i]) { return false; } } return true; } private static string GetID (byte[] bytes) { string id = ""; for (int i = 0; i < bytes.Length; i++) { id += (char)bytes[i]; } return id; } private static string ReadString (BinaryReader br) { int len = br.ReadInt32(); byte[] bytes = br.ReadBytes(len); string str = ""; for (int i = 0; i < bytes.Length; i++) { str += (char)bytes[i]; } return str; } // Dic private static Dictionary ReadDictionary (BinaryReader br) { var dic = new Dictionary(); int len = br.ReadInt32(); for (int i = 0; i < len; i++) { string key = ReadString(br); string value = ReadString(br); dic.Add(key, value); } return dic; } private static float TryGetFloat (Dictionary dic, string key, float defaultValue) { float res; if (dic.ContainsKey(key) && float.TryParse(dic[key], out res)) { return res; } return defaultValue; } private static int TryGetInt (Dictionary dic, string key, int defaultValue) { int res; if (dic.ContainsKey(key) && int.TryParse(dic[key], out res)) { return res; } return defaultValue; } private static string TryGetString (Dictionary dic, string key, string defaultValue) { return dic.ContainsKey(key) ? dic[key] : defaultValue; } private static byte TryGetByte (Dictionary dic, string key, byte defaultValue) { byte res; if (dic.ContainsKey(key) && byte.TryParse(dic[key], out res)) { return res; } return defaultValue; } private static Vector3 TryGetVector3 (Dictionary dic, string key, Vector3 defaultValue) { if (dic.ContainsKey(key)) { string[] valueStr = dic[key].Split(' '); Vector3 vector = Vector3.zero; if (valueStr.Length == 3) { for (int i = 0; i < 3; i++) { int value; if (int.TryParse(valueStr[i], out value)) { vector[i] = value; } else { return defaultValue; } } return Util.SwipYZ(vector); } } return defaultValue; } // Chrunk private static byte[] ToChrunkByte (List source, string id) { int len = source.Count; source.InsertRange(0, GetBytes(0)); source.InsertRange(0, GetBytes(len)); source.InsertRange(0, Encoding.Default.GetBytes(id)); return source.ToArray(); } // Matrix public static void VoxMatrixByteToTransform (byte mByte, out Vector3 rotation, out Vector3 scale) { Util.VoxMatrixByteToTransform(mByte, out rotation, out scale); } private static string TransformToVoxMatrixByteString (Vector3 rot, Vector3 scale) { return Util.TransformToVoxMatrixByte(rot, scale).ToString(); } // Qb private static int ColorToInt (Color color) { return ( ((int)(color.a * 255) << 24) | ((int)(color.b * 255) << 16) | ((int)(color.g * 255) << 8) | ((int)(color.r * 255) << 0) ); } #endregion } }