public static void CombineVoxels(MVVoxModelVoxel[] voxels) {
		if (voxels != null && voxels.Length > 0) {
			MVVoxelChunk chunk = new MVVoxelChunk ();
			MVVoxModel model = voxels [0].parentVoxModel;
			MVVoxelChunk origChunk = model.vox.voxelChunk;

			chunk.voxels = new byte[origChunk.sizeX, origChunk.sizeY, origChunk.sizeZ];
			foreach (MVVoxModelVoxel v in voxels) {
				chunk.voxels [v.voxel.x, v.voxel.y, v.voxel.z] = v.voxel.colorIndex;
			}

			MVImporter.GenerateFaces(chunk, model.vox.alphaMaskChunk);
			Mesh[] meshes = MVImporter.CreateMeshesFromChunk(chunk, model.vox.palatte, model.sizePerVox, model.vox.alphaMaskChunk);

			if (meshes.Length > 1) {
				Debug.LogError ("[MVCombine] Currently does not support combining voxels into multiple meshes, please reduce the number of voxels you are trying to combine");
				return;
			}

			Material mat = (model.voxMaterial != null) ? model.voxMaterial : MVImporter.DefaultMaterial;

			int index = 0;
			foreach (Mesh mesh in meshes) {
				GameObject go = MVImporter.CreateGameObject (model.gameObject.transform, Vector3.zero, string.Format ("VoxMesh ({0})", index), mesh, mat);

				MVVoxModelMesh voxMesh = go.AddComponent<MVVoxModelMesh> ();
				voxMesh.voxels = voxels.Select( o => o.voxel ).ToArray();

				Selection.activeGameObject = go;

				index++;
			}

			foreach (MVVoxModelVoxel v in voxels) {
				GameObject.DestroyImmediate (v.gameObject);
			}
		}
		else {
			Debug.LogError("[MVCombine] Invalid voxels");
		}
	}
    public static Mesh[] CreateMeshesFromChunk(MVVoxelChunk chunk, Color[] palatte, float sizePerVox, MVVoxelChunk alphaMask)
    {
        Vector3 origin = new Vector3(
            (float)chunk.sizeX / 2,
            (float)chunk.sizeY / 2,
            (float)chunk.sizeZ / 2);

        return(CreateMeshesFromChunk(chunk, palatte, sizePerVox, alphaMask, origin));
    }
    public static GameObject[] CreateVoxelGameObjectsForChunk(MVVoxelChunk chunk, Color[] palatte, Transform parent, Material mat, float sizePerVox, MVVoxelChunk alphaMask, Vector3 origin)
    {
        List <GameObject> result = new List <GameObject> ();

        Mesh[] meshes = CreateMeshesFromChunk(chunk, palatte, sizePerVox, alphaMask, origin);

        int index = 0;

        foreach (Mesh mesh in meshes)
        {
            GameObject go = new GameObject();
            go.name = string.Format("VoxelMesh ({0})", index);
            go.transform.SetParent(parent);
            go.transform.localPosition = Vector3.zero;
            go.transform.localRotation = Quaternion.Euler(Vector3.zero);
            go.transform.localScale    = Vector3.one;

            MeshFilter mf = go.AddComponent <MeshFilter> ();
            mf.mesh = mesh;

            MeshRenderer mr = go.AddComponent <MeshRenderer> ();
            mr.material = mat;

            go.AddComponent <MVVoxModelMesh> ();
            result.Add(go);
            index++;
        }

        return(result.ToArray());
    }
    public static GameObject[] CreateVoxelGameObjectsForChunk(MVVoxelChunk chunk, Color[] palatte, Transform parent, Material mat, float sizePerVox, MVVoxelChunk alphaMask)
    {
        Vector3 origin = new Vector3(
            (float)chunk.sizeX / 2,
            (float)chunk.sizeY / 2,
            (float)chunk.sizeZ / 2);

        return(CreateVoxelGameObjectsForChunk(chunk, palatte, parent, mat, sizePerVox, alphaMask, origin));
    }
    public static GameObject[] CreateIndividualVoxelGameObjectsForChunk(MVVoxelChunk chunk, Color[] palatte, Transform parent, Material mat, float sizePerVox, MVVoxelChunk alphaMask, Vector3 origin)
    {
        List <GameObject> result = new List <GameObject> ();

        if (alphaMask != null && (alphaMask.sizeX != chunk.sizeX || alphaMask.sizeY != chunk.sizeY || alphaMask.sizeZ != chunk.sizeZ))
        {
            Debug.LogErrorFormat("Unable to create meshes from chunk : Chunk's size ({0},{1},{2}) differs from alphaMask chunk's size ({3},{4},{5})", chunk.sizeX, chunk.sizeY, chunk.sizeZ, alphaMask.sizeX, alphaMask.sizeY, alphaMask.sizeZ);
            return(result.ToArray());
        }

        for (int x = 0; x < chunk.sizeX; ++x)
        {
            for (int y = 0; y < chunk.sizeY; ++y)
            {
                for (int z = 0; z < chunk.sizeZ; ++z)
                {
                    if (chunk.voxels [x, y, z] != 0)
                    {
                        float px = (x - origin.x + 0.5f) * sizePerVox, py = (y - origin.y + 0.5f) * sizePerVox, pz = (z - origin.z + 0.5f) * sizePerVox;
                        Color c = palatte [chunk.voxels [x, y, z] - 1];

                        if (alphaMask != null && alphaMask.voxels != null && alphaMask.voxels[x, y, z] != 0)
                        {
                            c.a = (float)(alphaMask.voxels [x, y, z] - 1) / 255;
                        }

                        GameObject go = CreateGameObject(
                            parent,
                            new Vector3(px, py, pz),
                            string.Format("Voxel ({0}, {1}, {2})", x, y, z),
                            MVImporter.CubeMeshWithColor(sizePerVox, c),
                            mat);

                        MVVoxModelVoxel v = go.AddComponent <MVVoxModelVoxel> ();
                        v.voxel = new MVVoxel()
                        {
                            x = (byte)x, y = (byte)y, z = (byte)z, colorIndex = chunk.voxels [x, y, z]
                        };

                        result.Add(go);
                    }
                }
            }
        }

        return(result.ToArray());
    }
	public static MVMainChunk LoadVOX(string path, MVVoxelChunk alphaMask = null, bool generateFaces = true)
	{
		byte[] bytes = File.ReadAllBytes (path);
		if (bytes [0] != 'V' ||
			bytes [1] != 'O' ||
			bytes [2] != 'X' ||
			bytes [3] != ' ') {
			Debug.LogError ("Invalid VOX file, magic number mismatch");
			return null;
		}

		return LoadVOXFromData (bytes, alphaMask, generateFaces);
	}
	private static bool DetermineEmptyOrOtherAlphaVoxel(MVVoxelChunk voxelChunk, MVVoxelChunk alphaMask, int a, int x, int y, int z)
	{
		bool isEmpty = voxelChunk.voxels[x, y, z] == 0;

		if (alphaMask == null)
			return isEmpty;
		else
		{
			bool otherAlpha = alphaMask.voxels[x, y, z] != a;
			return isEmpty || otherAlpha;
		}
	}
	public static Mesh[] CreateMeshesFromChunk(MVVoxelChunk chunk, Color[] palatte, float sizePerVox, MVVoxelChunk alphaMask)
	{
		Vector3 origin = new Vector3(
			(float)chunk.sizeX / 2,
			(float)chunk.sizeY / 2,
			(float)chunk.sizeZ / 2);

		return CreateMeshesFromChunk(chunk, palatte, sizePerVox, alphaMask, origin);
	}
	public static Mesh[] CreateMeshesFromChunk(MVVoxelChunk chunk, Color[] palatte, float sizePerVox, MVVoxelChunk alphaMask, Vector3 origin)
	{
		if (alphaMask != null && (alphaMask.sizeX != chunk.sizeX || alphaMask.sizeY != chunk.sizeY || alphaMask.sizeZ != chunk.sizeZ))
		{
			Debug.LogErrorFormat("Unable to create meshes from chunk : Chunk's size ({0},{1},{2}) differs from alphaMask chunk's size ({3},{4},{5})", chunk.sizeX, chunk.sizeY, chunk.sizeZ, alphaMask.sizeX, alphaMask.sizeY, alphaMask.sizeZ);
			return new Mesh[] { };
		}

		List<Vector3> verts = new List<Vector3> ();
		List<Vector3> normals = new List<Vector3> ();
		List<Color> colors = new List<Color> ();
		List<int> indicies = new List<int> ();

		Vector3[] faceNormals = new Vector3[] {
			Vector3.right,
			Vector3.left,
			Vector3.up,
			Vector3.down,
			Vector3.forward,
			Vector3.back
		};

		List<Mesh> result = new List<Mesh> ();

		if (sizePerVox <= 0.0f)
			sizePerVox = 0.1f;
		
		float halfSize = sizePerVox / 2.0f;

		int currentQuadCount = 0;
		int totalQuadCount = 0;
		for (int f = 0; f < 6; ++f) {
			for (int x = 0; x < chunk.sizeX; ++x) {
				for (int y = 0; y < chunk.sizeY; ++y) {
					for (int z = 0; z < chunk.sizeZ; ++z) {

						int cidx = chunk.faces [f].colorIndices [x, y, z];
						int alpha = alphaMask == null ? (byte)0 : alphaMask.voxels[x, y, z];

						if (cidx != 0) {
							float px = (x - origin.x + 0.5f) * sizePerVox, py = (y - origin.y + 0.5f) * sizePerVox, pz = (z - origin.z + 0.5f) * sizePerVox;

							int rx = x, ry = y, rz = z;
							switch (f) {
							case 1:
							case 0:
								{
									ry = y + 1;
									while (ry < chunk.sizeY && CompareColor(cidx, alpha, chunk, alphaMask, f, x, ry, z))
										ry++;
									ry--;

									rz = z + 1;
									while (rz < chunk.sizeZ) {
										bool inc = true;
										for (int k = y; k <= ry; ++k) {
											inc = inc & (CompareColor(cidx, alpha, chunk, alphaMask, f, x, k, rz));
										}

										if (inc)
											rz++;
										else
											break;
									}
									rz--;
									break;
								}

							case 3:
							case 2:
								{
									rx = x + 1;
									while (rx < chunk.sizeX && CompareColor(cidx, alpha, chunk, alphaMask, f, rx, y, z))
										rx++;
									rx--;

									rz = z + 1;
									while (rz < chunk.sizeZ) {
										bool inc = true;
										for (int k = x; k <= rx; ++k) {
											inc = inc & (CompareColor(cidx, alpha, chunk, alphaMask, f, k, y, rz));
										}

										if (inc)
											rz++;
										else
											break;
									}
									rz--;
									break;
								}

							case 5:
							case 4:
								{
									rx = x + 1;
									while (rx < chunk.sizeX && CompareColor(cidx, alpha, chunk, alphaMask, f, rx, y, z))
										rx++;
									rx--;

									ry = y + 1;
									while (ry < chunk.sizeY) {
										bool inc = true;
										for (int k = x; k <= rx; ++k) {
											inc = inc & (CompareColor(cidx, alpha, chunk, alphaMask, f, k, ry, z));
										}

										if (inc)
											ry++;
										else
											break;
									}
									ry--;
									break;
								}
							}


							for (int kx = x; kx <= rx; ++kx) {
								for (int ky = y; ky <= ry; ++ky) {
									for (int kz = z; kz <= rz; ++kz) {
										if(kx != x || ky != y || kz != z)
											chunk.faces [f].colorIndices [kx, ky, kz] = 0;
									}
								}
							}

							int dx = rx - x;
							int dy = ry - y;
							int dz = rz - z;

							switch (f) {
							case 1:
								verts.Add (new Vector3 (px - halfSize, py - halfSize, pz - halfSize));
								verts.Add (new Vector3 (px - halfSize, py - halfSize, pz + halfSize + sizePerVox * dz));
								verts.Add (new Vector3 (px - halfSize, py + halfSize + sizePerVox * dy, pz + halfSize + sizePerVox * dz));
								verts.Add (new Vector3 (px - halfSize, py + halfSize + sizePerVox * dy, pz - halfSize));
								break;

							case 0:
								verts.Add (new Vector3 (px + halfSize, py - halfSize, pz - halfSize));
								verts.Add (new Vector3 (px + halfSize, py + halfSize + sizePerVox * dy, pz - halfSize));
								verts.Add (new Vector3 (px + halfSize, py + halfSize + sizePerVox * dy, pz + halfSize + sizePerVox * dz));
								verts.Add (new Vector3 (px + halfSize, py - halfSize, pz + halfSize + sizePerVox * dz));
								break;

							case 3:
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py - halfSize, pz - halfSize));
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py - halfSize, pz + halfSize + sizePerVox * dz));
								verts.Add (new Vector3 (px - halfSize, py - halfSize, pz + halfSize + sizePerVox * dz));
								verts.Add (new Vector3 (px - halfSize, py - halfSize, pz - halfSize));
								break;

							case 2:
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py + halfSize, pz - halfSize));
								verts.Add (new Vector3 (px - halfSize, py + halfSize, pz - halfSize));
								verts.Add (new Vector3 (px - halfSize, py + halfSize, pz + halfSize + sizePerVox * dz));
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py + halfSize, pz + halfSize + sizePerVox * dz));
								break;

							case 5:
								verts.Add (new Vector3 (px - halfSize, py + halfSize + sizePerVox * dy, pz - halfSize));
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py + halfSize + sizePerVox * dy, pz - halfSize));
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py - halfSize, pz - halfSize));
								verts.Add (new Vector3 (px - halfSize, py - halfSize, pz - halfSize));
								break;

							case 4:
								verts.Add (new Vector3 (px - halfSize, py + halfSize + sizePerVox * dy, pz + halfSize));
								verts.Add (new Vector3 (px - halfSize, py - halfSize, pz + halfSize));
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py - halfSize, pz + halfSize));
								verts.Add (new Vector3 (px + halfSize + sizePerVox * dx, py + halfSize + sizePerVox * dy, pz + halfSize));
								break;
							}

							normals.Add (faceNormals [f]);
							normals.Add (faceNormals [f]);
							normals.Add (faceNormals [f]);
							normals.Add (faceNormals [f]);

							// color index starts with 1
							Color c = palatte [cidx - 1];

							if (alpha != 0)
								c.a = (float)(alpha - 1) / 255;

							colors.Add (c);
							colors.Add (c);
							colors.Add (c);
							colors.Add (c);

							indicies.Add (currentQuadCount * 4 + 0);
							indicies.Add (currentQuadCount * 4 + 1);
							indicies.Add (currentQuadCount * 4 + 2);
							indicies.Add (currentQuadCount * 4 + 2);
							indicies.Add (currentQuadCount * 4 + 3);
							indicies.Add (currentQuadCount * 4 + 0);

							currentQuadCount += 1;

							// u3d max
							if (verts.Count + 4 >= 65000) {
								Mesh mesh = new Mesh ();
								mesh.vertices = verts.ToArray();
								mesh.colors = colors.ToArray();
								mesh.normals = normals.ToArray();
								mesh.triangles = indicies.ToArray ();
								mesh.Optimize ();
								result.Add (mesh);

								verts.Clear ();
								colors.Clear ();
								normals.Clear ();
								indicies.Clear ();

								totalQuadCount += currentQuadCount;
								currentQuadCount = 0;
							}
						}
					}
				}
			}
		}

		if (verts.Count > 0) {
			Mesh mesh = new Mesh ();
			mesh.vertices = verts.ToArray();
			mesh.colors = colors.ToArray();
			mesh.normals = normals.ToArray();
			mesh.triangles = indicies.ToArray ();
			mesh.Optimize ();
			result.Add (mesh);

			totalQuadCount += currentQuadCount;
		}

		Debug.Log (string.Format ("[MVImport] Mesh generated, total quads {0}", totalQuadCount));

		return result.ToArray();
	}
	public static GameObject[] CreateVoxelGameObjectsForChunk(MVVoxelChunk chunk, Color[] palatte, Transform parent, Material mat, float sizePerVox, MVVoxelChunk alphaMask)
	{
		Vector3 origin = new Vector3(
			(float)chunk.sizeX / 2,
			(float)chunk.sizeY / 2,
			(float)chunk.sizeZ / 2);

		return CreateVoxelGameObjectsForChunk(chunk, palatte, parent, mat, sizePerVox, alphaMask, origin);
	}
	public static GameObject[] CreateVoxelGameObjectsForChunk(MVVoxelChunk chunk, Color[] palatte, Transform parent, Material mat, float sizePerVox, MVVoxelChunk alphaMask, Vector3 origin) {
		List<GameObject> result = new List<GameObject> ();

		Mesh[] meshes = CreateMeshesFromChunk (chunk, palatte, sizePerVox, alphaMask, origin);

		int index = 0;
		foreach (Mesh mesh in meshes) {
			GameObject go = new GameObject ();
			go.name = string.Format ("VoxelMesh ({0})", index);
			go.transform.SetParent (parent);
			go.transform.localPosition = Vector3.zero;

			MeshFilter mf = go.AddComponent<MeshFilter> ();
			mf.mesh = mesh;

			MeshRenderer mr = go.AddComponent<MeshRenderer> ();
			mr.material = mat;

			go.AddComponent<MVVoxModelMesh> ();
			result.Add (go);
			index++;
		}

		return result.ToArray ();
	}
	public static GameObject[] CreateIndividualVoxelGameObjectsForChunk(MVVoxelChunk chunk, Color[] palatte, Transform parent, Material mat, float sizePerVox, MVVoxelChunk alphaMask, Vector3 origin) {
		List<GameObject> result = new List<GameObject> ();

		if (alphaMask != null && (alphaMask.sizeX != chunk.sizeX || alphaMask.sizeY != chunk.sizeY || alphaMask.sizeZ != chunk.sizeZ))
		{
			Debug.LogErrorFormat("Unable to create meshes from chunk : Chunk's size ({0},{1},{2}) differs from alphaMask chunk's size ({3},{4},{5})", chunk.sizeX, chunk.sizeY, chunk.sizeZ, alphaMask.sizeX, alphaMask.sizeY, alphaMask.sizeZ);
			return result.ToArray();
		}

		for (int x = 0; x < chunk.sizeX; ++x) {
			for (int y = 0; y < chunk.sizeY; ++y) {
				for (int z = 0; z < chunk.sizeZ; ++z) {

					if (chunk.voxels [x, y, z] != 0) {
						float px = (x - origin.x + 0.5f) * sizePerVox, py = (y - origin.y + 0.5f) * sizePerVox, pz = (z - origin.z + 0.5f) * sizePerVox;
						Color c = palatte [chunk.voxels [x, y, z] - 1];

						if (alphaMask != null && alphaMask.voxels[x, y, z] != 0)
							c.a = (float)(alphaMask.voxels [x, y, z] - 1) / 255;

						GameObject go = CreateGameObject (
							parent, 
							new Vector3 (px, py, pz),
							string.Format ("Voxel ({0}, {1}, {2})", x, y, z),
							MVImporter.CubeMeshWithColor (sizePerVox, c),
							mat);

						MVVoxModelVoxel v = go.AddComponent<MVVoxModelVoxel> ();
						v.voxel = new MVVoxel () { x = (byte)x, y = (byte)y, z = (byte)z, colorIndex = chunk.voxels [x, y, z] };

						result.Add (go);
					}
				}
			}
		}

		return result.ToArray();
	}
	static int ReadVoxelChunk(BinaryReader br, MVVoxelChunk chunk)
	{
		int chunkSize = br.ReadInt32 ();
		int childrenSize = br.ReadInt32 ();
		int numVoxels = br.ReadInt32 ();

		for (int i = 0; i < numVoxels; ++i) {
			int x = (int)br.ReadByte ();
			int z = (int)br.ReadByte ();
			int y = (int)br.ReadByte ();

			chunk.voxels [x, y, z] = br.ReadByte();
		}

		if (childrenSize > 0) {
			br.ReadBytes (childrenSize);
			Debug.LogWarning ("[MVImporter] Nested chunk not supported");
		}

		return chunkSize + childrenSize + 4 * 3;
	}
	public static void GenerateFaces(MVVoxelChunk voxelChunk, MVVoxelChunk alphaMask)
	{
		voxelChunk.faces = new MVFaceCollection[6];
		for (int i = 0; i < 6; ++i) {
			voxelChunk.faces [i].colorIndices = new byte[voxelChunk.sizeX, voxelChunk.sizeY, voxelChunk.sizeZ];
		}

		for (int x = 0; x < voxelChunk.sizeX; ++x) {
			for (int y = 0; y < voxelChunk.sizeY; ++y) {
				for (int z = 0; z < voxelChunk.sizeZ; ++z) {
					
					int alpha = alphaMask == null ? (byte)0 : alphaMask.voxels[x, y, z];

					// left right
					if (x == 0 || DetermineEmptyOrOtherAlphaVoxel(voxelChunk, alphaMask, alpha, x - 1, y, z))
						voxelChunk.faces [(int)MVFaceDir.XNeg].colorIndices [x, y, z] = voxelChunk.voxels [x, y, z];

					if (x == voxelChunk.sizeX - 1 || DetermineEmptyOrOtherAlphaVoxel(voxelChunk, alphaMask, alpha, x + 1, y, z))
						voxelChunk.faces [(int)MVFaceDir.XPos].colorIndices [x, y, z] = voxelChunk.voxels [x, y, z];

					// up down
					if (y == 0 || DetermineEmptyOrOtherAlphaVoxel(voxelChunk, alphaMask, alpha, x, y - 1, z))
						voxelChunk.faces [(int)MVFaceDir.YNeg].colorIndices [x, y, z] = voxelChunk.voxels [x, y, z];

					if (y == voxelChunk.sizeY - 1 || DetermineEmptyOrOtherAlphaVoxel(voxelChunk, alphaMask, alpha, x, y + 1, z))
						voxelChunk.faces [(int)MVFaceDir.YPos].colorIndices [x, y, z] = voxelChunk.voxels [x, y, z];

					// forward backward
					if (z == 0 || DetermineEmptyOrOtherAlphaVoxel(voxelChunk, alphaMask, alpha, x, y, z - 1))
						voxelChunk.faces [(int)MVFaceDir.ZNeg].colorIndices [x, y, z] = voxelChunk.voxels [x, y, z];

					if (z == voxelChunk.sizeZ - 1 || DetermineEmptyOrOtherAlphaVoxel(voxelChunk, alphaMask, alpha, x, y, z + 1))
						voxelChunk.faces [(int)MVFaceDir.ZPos].colorIndices [x, y, z] = voxelChunk.voxels [x, y, z];
				}
			}
		}
	}
    public static Mesh[] CreateMeshesFromChunk(MVVoxelChunk chunk, Color[] palatte, float sizePerVox, MVVoxelChunk alphaMask, Vector3 origin)
    {
        if (alphaMask != null && alphaMask.voxels != null && (alphaMask.sizeX != chunk.sizeX || alphaMask.sizeY != chunk.sizeY || alphaMask.sizeZ != chunk.sizeZ))
        {
            Debug.LogErrorFormat("Unable to create meshes from chunk : Chunk's size ({0},{1},{2}) differs from alphaMask chunk's size ({3},{4},{5})", chunk.sizeX, chunk.sizeY, chunk.sizeZ, alphaMask.sizeX, alphaMask.sizeY, alphaMask.sizeZ);
            return(new Mesh[] { });
        }

        List <Vector3> verts    = new List <Vector3> ();
        List <Vector3> normals  = new List <Vector3> ();
        List <Color>   colors   = new List <Color> ();
        List <int>     indicies = new List <int> ();

        Vector3[] faceNormals = new Vector3[] {
            Vector3.right,
            Vector3.left,
            Vector3.up,
            Vector3.down,
            Vector3.forward,
            Vector3.back
        };

        List <Mesh> result = new List <Mesh> ();

        if (sizePerVox <= 0.0f)
        {
            sizePerVox = 0.1f;
        }

        float halfSize = sizePerVox / 2.0f;

        int currentQuadCount = 0;
        int totalQuadCount   = 0;

        for (int f = 0; f < 6; ++f)
        {
            for (int x = 0; x < chunk.sizeX; ++x)
            {
                for (int y = 0; y < chunk.sizeY; ++y)
                {
                    for (int z = 0; z < chunk.sizeZ; ++z)
                    {
                        int cidx  = chunk.faces [f].colorIndices [x, y, z];
                        int alpha = 0;
                        if (alphaMask == null && alphaMask.voxels != null)
                        {
                            alpha = alphaMask.voxels[x, y, z];
                        }


                        if (cidx != 0)
                        {
                            float px = (x - origin.x + 0.5f) * sizePerVox, py = (y - origin.y + 0.5f) * sizePerVox, pz = (z - origin.z + 0.5f) * sizePerVox;

                            int rx = x, ry = y, rz = z;
                            switch (f)
                            {
                            case 1:
                            case 0:
                            {
                                ry = y + 1;
                                while (ry < chunk.sizeY && CompareColor(cidx, alpha, chunk, alphaMask, f, x, ry, z))
                                {
                                    ry++;
                                }
                                ry--;

                                rz = z + 1;
                                while (rz < chunk.sizeZ)
                                {
                                    bool inc = true;
                                    for (int k = y; k <= ry; ++k)
                                    {
                                        inc = inc & (CompareColor(cidx, alpha, chunk, alphaMask, f, x, k, rz));
                                    }

                                    if (inc)
                                    {
                                        rz++;
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                rz--;
                                break;
                            }

                            case 3:
                            case 2:
                            {
                                rx = x + 1;
                                while (rx < chunk.sizeX && CompareColor(cidx, alpha, chunk, alphaMask, f, rx, y, z))
                                {
                                    rx++;
                                }
                                rx--;

                                rz = z + 1;
                                while (rz < chunk.sizeZ)
                                {
                                    bool inc = true;
                                    for (int k = x; k <= rx; ++k)
                                    {
                                        inc = inc & (CompareColor(cidx, alpha, chunk, alphaMask, f, k, y, rz));
                                    }

                                    if (inc)
                                    {
                                        rz++;
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                rz--;
                                break;
                            }

                            case 5:
                            case 4:
                            {
                                rx = x + 1;
                                while (rx < chunk.sizeX && CompareColor(cidx, alpha, chunk, alphaMask, f, rx, y, z))
                                {
                                    rx++;
                                }
                                rx--;

                                ry = y + 1;
                                while (ry < chunk.sizeY)
                                {
                                    bool inc = true;
                                    for (int k = x; k <= rx; ++k)
                                    {
                                        inc = inc & (CompareColor(cidx, alpha, chunk, alphaMask, f, k, ry, z));
                                    }

                                    if (inc)
                                    {
                                        ry++;
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                ry--;
                                break;
                            }
                            }


                            for (int kx = x; kx <= rx; ++kx)
                            {
                                for (int ky = y; ky <= ry; ++ky)
                                {
                                    for (int kz = z; kz <= rz; ++kz)
                                    {
                                        if (kx != x || ky != y || kz != z)
                                        {
                                            chunk.faces [f].colorIndices [kx, ky, kz] = 0;
                                        }
                                    }
                                }
                            }

                            int dx = rx - x;
                            int dy = ry - y;
                            int dz = rz - z;

                            switch (f)
                            {
                            case 1:
                                verts.Add(new Vector3(px - halfSize, py - halfSize, pz - halfSize));
                                verts.Add(new Vector3(px - halfSize, py - halfSize, pz + halfSize + sizePerVox * dz));
                                verts.Add(new Vector3(px - halfSize, py + halfSize + sizePerVox * dy, pz + halfSize + sizePerVox * dz));
                                verts.Add(new Vector3(px - halfSize, py + halfSize + sizePerVox * dy, pz - halfSize));
                                break;

                            case 0:
                                verts.Add(new Vector3(px + halfSize, py - halfSize, pz - halfSize));
                                verts.Add(new Vector3(px + halfSize, py + halfSize + sizePerVox * dy, pz - halfSize));
                                verts.Add(new Vector3(px + halfSize, py + halfSize + sizePerVox * dy, pz + halfSize + sizePerVox * dz));
                                verts.Add(new Vector3(px + halfSize, py - halfSize, pz + halfSize + sizePerVox * dz));
                                break;

                            case 3:
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py - halfSize, pz - halfSize));
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py - halfSize, pz + halfSize + sizePerVox * dz));
                                verts.Add(new Vector3(px - halfSize, py - halfSize, pz + halfSize + sizePerVox * dz));
                                verts.Add(new Vector3(px - halfSize, py - halfSize, pz - halfSize));
                                break;

                            case 2:
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py + halfSize, pz - halfSize));
                                verts.Add(new Vector3(px - halfSize, py + halfSize, pz - halfSize));
                                verts.Add(new Vector3(px - halfSize, py + halfSize, pz + halfSize + sizePerVox * dz));
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py + halfSize, pz + halfSize + sizePerVox * dz));
                                break;

                            case 5:
                                verts.Add(new Vector3(px - halfSize, py + halfSize + sizePerVox * dy, pz - halfSize));
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py + halfSize + sizePerVox * dy, pz - halfSize));
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py - halfSize, pz - halfSize));
                                verts.Add(new Vector3(px - halfSize, py - halfSize, pz - halfSize));
                                break;

                            case 4:
                                verts.Add(new Vector3(px - halfSize, py + halfSize + sizePerVox * dy, pz + halfSize));
                                verts.Add(new Vector3(px - halfSize, py - halfSize, pz + halfSize));
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py - halfSize, pz + halfSize));
                                verts.Add(new Vector3(px + halfSize + sizePerVox * dx, py + halfSize + sizePerVox * dy, pz + halfSize));
                                break;
                            }

                            normals.Add(faceNormals [f]);
                            normals.Add(faceNormals [f]);
                            normals.Add(faceNormals [f]);
                            normals.Add(faceNormals [f]);

                            // color index starts with 1
                            Color c = palatte [cidx - 1];

                            if (alpha != 0)
                            {
                                c.a = (float)(alpha - 1) / 255;
                            }

                            colors.Add(c);
                            colors.Add(c);
                            colors.Add(c);
                            colors.Add(c);

                            indicies.Add(currentQuadCount * 4 + 0);
                            indicies.Add(currentQuadCount * 4 + 1);
                            indicies.Add(currentQuadCount * 4 + 2);
                            indicies.Add(currentQuadCount * 4 + 2);
                            indicies.Add(currentQuadCount * 4 + 3);
                            indicies.Add(currentQuadCount * 4 + 0);

                            currentQuadCount += 1;

                            // u3d max
                            if (verts.Count + 4 >= 65000)
                            {
                                Mesh mesh = new Mesh();
                                mesh.vertices  = verts.ToArray();
                                mesh.colors    = colors.ToArray();
                                mesh.normals   = normals.ToArray();
                                mesh.triangles = indicies.ToArray();

                                result.Add(mesh);

                                verts.Clear();
                                colors.Clear();
                                normals.Clear();
                                indicies.Clear();

                                totalQuadCount  += currentQuadCount;
                                currentQuadCount = 0;
                            }
                        }
                    }
                }
            }
        }

        if (verts.Count > 0)
        {
            Mesh mesh = new Mesh();
            mesh.vertices  = verts.ToArray();
            mesh.colors    = colors.ToArray();
            mesh.normals   = normals.ToArray();
            mesh.triangles = indicies.ToArray();

            result.Add(mesh);

            totalQuadCount += currentQuadCount;
        }

        Debug.Log(string.Format("[MVImport] Mesh generated, total quads {0}", totalQuadCount));

        return(result.ToArray());
    }
	private static bool CompareColor(int cidx, int alpha, MVVoxelChunk chunk, MVVoxelChunk alphaChunk, int f, int x, int y, int z)
	{
		if (alphaChunk == null)
			return chunk.faces[f].colorIndices[x, y, z] == cidx;
		else
			return chunk.faces[f].colorIndices[x, y, z] == cidx && alphaChunk.voxels[x, y, z] == alpha;
	}
Beispiel #17
0
    public static MVMainChunk LoadVOXFromData(byte[] data, MVVoxelChunk alphaMask = null, bool generateFaces = true)
    {
        using (MemoryStream ms = new MemoryStream(data)) {
            using (BinaryReader br = new BinaryReader(ms)) {
                MVMainChunk mainChunk = new MVMainChunk();

                // "VOX "
                br.ReadInt32();
                // "VERSION "
                mainChunk.version = br.ReadBytes(4);

                byte[] chunkId = br.ReadBytes(4);
                if (chunkId [0] != 'M' ||
                    chunkId [1] != 'A' ||
                    chunkId [2] != 'I' ||
                    chunkId [3] != 'N')
                {
                    Debug.LogError("[MVImport] Invalid MainChunk ID, main chunk expected");
                    return(null);
                }

                int chunkSize    = br.ReadInt32();
                int childrenSize = br.ReadInt32();

                // main chunk should have nothing... skip
                br.ReadBytes(chunkSize);

                int readSize = 0;
                while (readSize < childrenSize)
                {
                    chunkId = br.ReadBytes(4);

                    if (chunkId [0] == 'P' &&
                        chunkId [1] == 'A' &&
                        chunkId [2] == 'C' &&
                        chunkId [3] == 'K')
                    {
                        int chunkContentBytes = br.ReadInt32();
                        int childrenBytes     = br.ReadInt32();

                        int modelCount = br.ReadInt32();

                        readSize += chunkContentBytes + childrenBytes + 4 * 3;
                    }
                    else if (chunkId [0] == 'S' &&
                             chunkId [1] == 'I' &&
                             chunkId [2] == 'Z' &&
                             chunkId [3] == 'E')
                    {
                        readSize += ReadSizeChunk(br, mainChunk);
                    }
                    else if (chunkId [0] == 'X' &&
                             chunkId [1] == 'Y' &&
                             chunkId [2] == 'Z' &&
                             chunkId [3] == 'I')
                    {
                        readSize += ReadVoxelChunk(br, mainChunk.voxelChunk);
                    }
                    else if (chunkId [0] == 'R' &&
                             chunkId [1] == 'G' &&
                             chunkId [2] == 'B' &&
                             chunkId [3] == 'A')
                    {
                        mainChunk.palatte = new Color[256];
                        readSize         += ReadPalattee(br, mainChunk.palatte);
                    }
                    else
                    {
                        Debug.LogError("[MVImport] Chunk ID not recognized, got " + System.Text.Encoding.ASCII.GetString(chunkId));
                        return(null);
                    }
                }

                mainChunk.alphaMaskChunk = alphaMask;

                if (generateFaces)
                {
                    GenerateFaces(mainChunk.voxelChunk, alphaMask);
                }

                if (mainChunk.palatte == null)
                {
                    mainChunk.palatte = MVMainChunk.defaultPalatte;
                }

                return(mainChunk);
            }
        }
    }
	public static MVMainChunk LoadVOXFromData(byte[] data, MVVoxelChunk alphaMask = null, bool generateFaces = true) {
		using (MemoryStream ms = new MemoryStream (data)) {
			using (BinaryReader br = new BinaryReader (ms)) {
				MVMainChunk mainChunk = new MVMainChunk ();

				// "VOX "
				br.ReadInt32 ();
				// "VERSION "
				mainChunk.version = br.ReadBytes(4);

				byte[] chunkId = br.ReadBytes (4);
				if (chunkId [0] != 'M' ||
					chunkId [1] != 'A' ||
					chunkId [2] != 'I' ||
					chunkId [3] != 'N') {
					Debug.LogError ("[MVImport] Invalid MainChunk ID, main chunk expected");
					return null;
				}

				int chunkSize = br.ReadInt32 ();
				int childrenSize = br.ReadInt32 ();

				// main chunk should have nothing... skip
				br.ReadBytes (chunkSize); 

				int readSize = 0;
				while (readSize < childrenSize) {
					chunkId = br.ReadBytes (4);
					if (chunkId [0] == 'S' &&
						chunkId [1] == 'I' &&
						chunkId [2] == 'Z' &&
						chunkId [3] == 'E') {

						readSize += ReadSizeChunk (br, mainChunk);

					} else if (chunkId [0] == 'X' &&
						chunkId [1] == 'Y' &&
						chunkId [2] == 'Z' &&
						chunkId [3] == 'I') {

						readSize += ReadVoxelChunk (br, mainChunk.voxelChunk);

					} else if (chunkId [0] == 'R' &&
						chunkId [1] == 'G' &&
						chunkId [2] == 'B' &&
						chunkId [3] == 'A') {

						mainChunk.palatte = new Color[256];
						readSize += ReadPalattee (br, mainChunk.palatte);

					}
					else {
						Debug.LogError ("[MVImport] Chunk ID not recognized, got " + System.Text.Encoding.ASCII.GetString(chunkId));
						return null;
					}
				}

				mainChunk.alphaMaskChunk = alphaMask;

				if (generateFaces)
					GenerateFaces(mainChunk.voxelChunk, alphaMask);

				if (mainChunk.palatte == null)
					mainChunk.palatte = MVMainChunk.defaultPalatte;

				return mainChunk;
			}
		}
	}