2
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1042 lines
27 KiB
C#

2 years ago
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<Color> colors) {
colors = new List<Color>();
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<int, Dictionary<string, string>>[modelNum];
for (int i = 0; i < modelNum; i++) {
int modelId = _br.ReadInt32();
var modelAttr = ReadDictionary(_br);
modelData[i] = new KeyValuePair<int, Dictionary<string, string>>(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<VoxelData.RigData.Bone>(),
Weights = new List<VoxelData.RigData.Weight>(),
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<byte> voxByte = new List<byte>();
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<byte> bytes = new List<byte>();
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<int, byte[]>();
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<byte> bytes = new List<byte>();
bytes.AddRange(GetBytes(data.Voxels.Count));
return ToChrunkByte(bytes, "PACK");
}
private static byte[] WriteSize (int[,,] voxels) {
List<byte> bytes = new List<byte>();
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<byte> bytes = new List<byte>();
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<Color> palette) {
List<byte> bytes = new List<byte>();
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<byte> bytes = new List<byte>();
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<byte> bytes = new List<byte>();
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<byte> bytes = new List<byte>();
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<byte> bytes = new List<byte>();
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<byte> bytes = new List<byte>();
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<QbData.QbMatrix>();
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<byte> bytes = new List<byte>();
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<byte> 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<string, string> ReadDictionary (BinaryReader br) {
var dic = new Dictionary<string, string>();
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<string, string> 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<string, string> 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<string, string> dic, string key, string defaultValue) {
return dic.ContainsKey(key) ? dic[key] : defaultValue;
}
private static byte TryGetByte (Dictionary<string, string> 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<string, string> 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<byte> 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
}
}