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.
		
		
		
		
		
			
		
			
				
	
	
		
			1438 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			1438 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			C#
		
	
| namespace MagicaVoxelToolbox {
 | |
| 	using System.Collections;
 | |
| 	using System.Collections.Generic;
 | |
| 	using UnityEngine;
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public enum Direction {
 | |
| 		Up = 0,
 | |
| 		Down = 1,
 | |
| 		Left = 2,
 | |
| 		Right = 3,
 | |
| 		Front = 4,
 | |
| 		Back = 5,
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public class VoxelData {
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#region --- SUB ---
 | |
| 
 | |
| 
 | |
| 		[System.Serializable]
 | |
| 		public class MaterialData {
 | |
| 
 | |
| 
 | |
| 			public const int SHADER_NUM = 5;
 | |
| 			public const int SHADER_PROPERTY_NUM = 13;
 | |
| 			public static readonly Vector2[] SHADER_VALUE_REMAP_SOURCE = new Vector2[SHADER_PROPERTY_NUM] {
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 1),
 | |
| 				new Vector2(0, 4),
 | |
| 				new Vector2(0, 1),
 | |
| 			};
 | |
| 
 | |
| 
 | |
| 
 | |
| 			public enum MaterialType {
 | |
| 				Diffuse = 0,
 | |
| 				Metal = 1,
 | |
| 				Glass = 2,
 | |
| 				Emit = 3,
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			public MaterialType Type;
 | |
| 			public int Index;
 | |
| 			public float Weight;
 | |
| 			public float Rough;
 | |
| 			public float Spec;
 | |
| 			public float Ior;
 | |
| 			public float Att;
 | |
| 			public float Flux;
 | |
| 			public float LDR;
 | |
| 			public int Plastic;
 | |
| 
 | |
| 
 | |
| 			public static MaterialType GetTypeFromString (string voxStr) {
 | |
| 				switch (voxStr) {
 | |
| 					default:
 | |
| 					case "_diffuse":
 | |
| 						return MaterialType.Diffuse;
 | |
| 					case "_metal":
 | |
| 						return MaterialType.Metal;
 | |
| 					case "_glass":
 | |
| 						return MaterialType.Glass;
 | |
| 					case "_emit":
 | |
| 						return MaterialType.Emit;
 | |
| 				}
 | |
| 			}
 | |
| 			public static string GetStringFromType (MaterialType type) {
 | |
| 				switch (type) {
 | |
| 					default:
 | |
| 					case MaterialType.Diffuse:
 | |
| 						return "_diffuse";
 | |
| 					case MaterialType.Metal:
 | |
| 						return "_metal";
 | |
| 					case MaterialType.Glass:
 | |
| 						return "_glass";
 | |
| 					case MaterialType.Emit:
 | |
| 						return "_emit";
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			public bool IsSameWith (MaterialData other) {
 | |
| 				if (Type != other.Type) { return false; }
 | |
| 				switch (Type) {
 | |
| 					default:
 | |
| 					case MaterialType.Diffuse:
 | |
| 						return true;
 | |
| 					case MaterialType.Metal:
 | |
| 						return Weight == other.Weight && Rough == other.Rough && Spec == other.Spec && Plastic == other.Plastic;
 | |
| 					case MaterialType.Glass:
 | |
| 						return Weight == other.Weight && Rough == other.Rough && Ior == other.Ior && Att == other.Att;
 | |
| 					case MaterialType.Emit:
 | |
| 						return Weight == other.Weight && Flux == other.Flux && LDR == other.LDR;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		[System.Serializable]
 | |
| 		public class TransformData {
 | |
| 
 | |
| 			[System.Serializable]
 | |
| 			public class FrameData {
 | |
| 				public Vector3 Rotation;
 | |
| 				public Vector3 Position;
 | |
| 				public Vector3 Scale;
 | |
| 			}
 | |
| 
 | |
| 			public int ChildID;
 | |
| 			public int LayerID;
 | |
| 			public string Name;
 | |
| 			public bool Hidden;
 | |
| 			public int Reserved;
 | |
| 			public FrameData[] Frames;
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public class GroupData {
 | |
| 			public Dictionary<string, string> Attributes;
 | |
| 			public int[] ChildNodeId;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public class ShapeData {
 | |
| 			public Dictionary<string, string> Attributes;
 | |
| 			public KeyValuePair<int, Dictionary<string, string>>[] ModelData;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		[System.Serializable]
 | |
| 		public class RigData {
 | |
| 
 | |
| 
 | |
| 
 | |
| 			[System.Serializable]
 | |
| 			public class Bone {
 | |
| 
 | |
| 				[System.NonSerialized] public Bone Parent = null;
 | |
| 				[System.NonSerialized] public int ChildCount = 0;
 | |
| 
 | |
| 				public int ParentIndex;// root >> -1
 | |
| 				public string Name;
 | |
| 				public int PositionX;
 | |
| 				public int PositionY;
 | |
| 				public int PositionZ;
 | |
| 
 | |
| 				public static implicit operator bool (Bone bone) {
 | |
| 					return bone != null;
 | |
| 				}
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 
 | |
| 			[System.Serializable]
 | |
| 			public class Weight {
 | |
| 
 | |
| 				public int X;
 | |
| 				public int Y;
 | |
| 				public int Z;
 | |
| 				public int BoneIndexA = -1;
 | |
| 				public int BoneIndexB = -1;
 | |
| 
 | |
| 
 | |
| 
 | |
| 				public Weight () {
 | |
| 					X = 0;
 | |
| 					Y = 0;
 | |
| 					Z = 0;
 | |
| 					BoneIndexA = -1;
 | |
| 					BoneIndexB = -1;
 | |
| 				}
 | |
| 
 | |
| 
 | |
| 
 | |
| 				public Weight (int indexA, int indexB) {
 | |
| 					X = 0;
 | |
| 					Y = 0;
 | |
| 					Z = 0;
 | |
| 					BoneIndexA = indexA;
 | |
| 					BoneIndexB = indexB;
 | |
| 				}
 | |
| 
 | |
| 
 | |
| 
 | |
| 				public float GetWeight (int boneIndex) {
 | |
| 					float weight = 0f;
 | |
| 					if (boneIndex == BoneIndexA || boneIndex == BoneIndexB) {
 | |
| 						weight = 0.5f;
 | |
| 						if (BoneIndexA == -1 || BoneIndexB == -1) {
 | |
| 							weight = 1f;
 | |
| 						}
 | |
| 					}
 | |
| 					return weight;
 | |
| 				}
 | |
| 
 | |
| 
 | |
| 
 | |
| 				public void SetWeight (int boneIndex) {
 | |
| 					if (BoneIndexA == boneIndex || BoneIndexB == boneIndex) {
 | |
| 						return;
 | |
| 					} else if (BoneIndexA == -1) {
 | |
| 						BoneIndexA = boneIndex;
 | |
| 					} else if (BoneIndexB == -1) {
 | |
| 						BoneIndexB = boneIndex;
 | |
| 					} else {
 | |
| 						BoneIndexB = BoneIndexA;
 | |
| 						BoneIndexA = boneIndex;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 
 | |
| 
 | |
| 				public bool IndexEqualsTo (Weight other) {
 | |
| 					return (BoneIndexA == other.BoneIndexA && BoneIndexB == other.BoneIndexB) ||
 | |
| 						(BoneIndexA == other.BoneIndexB && BoneIndexB == other.BoneIndexA);
 | |
| 				}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 
 | |
| 			public const int CURRENT_VERSION = 1;
 | |
| 
 | |
| 
 | |
| 			public List<Bone> Bones;
 | |
| 			public List<Weight> Weights;
 | |
| 			public int Version = 0;
 | |
| 
 | |
| 
 | |
| 
 | |
| 			public void FixVersion () {
 | |
| 				if (Version == 0) {
 | |
| 					if (Bones != null) {
 | |
| 						for (int i = 0; i < Bones.Count; i++) {
 | |
| 							var bone = Bones[i];
 | |
| 							bone.PositionX *= 2;
 | |
| 							bone.PositionY *= 2;
 | |
| 							bone.PositionZ *= 2;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				Version = CURRENT_VERSION;
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 			public static List<Bone> GetHumanBones (Vector3 size, bool fullSize) {
 | |
| 
 | |
| 
 | |
| 				var bones = new List<Bone>();
 | |
| 
 | |
| 
 | |
| 				// Body
 | |
| 				var hip = GetNewBone("Hips", null, 0.5f - 1f / size.x, 0.5f - 1f / size.y, 0.5f - 1f / size.z, size);
 | |
| 				var spine = GetNewBone("Spine", hip, 0, 0.05f, 0, size);
 | |
| 				var chest = GetNewBone("Chest", spine, 0, 0.05f, 0, size);
 | |
| 				var _upperChest = GetNewBone("UpperChest", chest, 0, 0.05f, 0, size);
 | |
| 				var neck = GetNewBone("Neck", fullSize ? _upperChest : chest, 0, 0.15f, 0, size);
 | |
| 				var head = GetNewBone("Head", neck, 0, 0.05f, 0, size);
 | |
| 
 | |
| 
 | |
| 				// Head
 | |
| 				var _eyeL = GetNewBone("LeftEye", head, -0.1f, 0.1f, 0, size);
 | |
| 				var _eyeR = GetNewBone("RightEye", head, 0.1f, 0.1f, 0, size);
 | |
| 				var _jaw = GetNewBone("Jaw", head, 0, 0.05f, 0, size);
 | |
| 
 | |
| 
 | |
| 				// Arm
 | |
| 				var _leftShoulder = GetNewBone("LeftShoulder", _upperChest, -0.05f, 0, 0, size);
 | |
| 				var _rightShoulder = GetNewBone("RightShoulder", _upperChest, 0.05f, 0, 0, size);
 | |
| 
 | |
| 				var armUL = GetNewBone("LeftUpperArm", fullSize ? _leftShoulder : chest, -0.1f, 0.05f, 0, size);
 | |
| 				var armUR = GetNewBone("RightUpperArm", fullSize ? _rightShoulder : chest, 0.1f, 0.05f, 0, size);
 | |
| 
 | |
| 				var armDL = GetNewBone("LeftLowerArm", armUL, -0.2f, 0, 0, size);
 | |
| 				var armDR = GetNewBone("RightLowerArm", armUR, 0.2f, 0, 0, size);
 | |
| 
 | |
| 				var handL = GetNewBone("LeftHand", armDL, -0.2f, 0, 0, size);
 | |
| 				var handR = GetNewBone("RightHand", armDR, 0.2f, 0, 0, size);
 | |
| 
 | |
| 
 | |
| 				// Leg
 | |
| 				var legUL = GetNewBone("LeftUpperLeg", hip, -0.05f, 0, 0, size);
 | |
| 				var legUR = GetNewBone("RightUpperLeg", hip, 0.05f, 0, 0, size);
 | |
| 
 | |
| 				var legDL = GetNewBone("LeftLowerLeg", legUL, 0, -0.25f, 0, size);
 | |
| 				var legDR = GetNewBone("RightLowerLeg", legUR, 0, -0.25f, 0, size);
 | |
| 
 | |
| 				var footL = GetNewBone("LeftFoot", legDL, 0, -0.25f, 0, size);
 | |
| 				var footR = GetNewBone("RightFoot", legDR, 0, -0.25f, 0, size);
 | |
| 
 | |
| 				var _toeL = GetNewBone("LeftToes", footL, 0, 0, -0.05f, size);
 | |
| 				var _toeR = GetNewBone("RightToes", footR, 0, 0, -0.05f, size);
 | |
| 
 | |
| 
 | |
| 
 | |
| 				// Hand   
 | |
| 				// Proximal > Intermediate > Distal
 | |
| 				// Thumb Index Middle Ring Little
 | |
| 				var _thumbProximalL = GetNewBone("Left Thumb Proximal", handL, -0.05f, 0, 0, size);
 | |
| 				var _thumbProximalR = GetNewBone("Right Thumb Proximal", handR, 0.05f, 0, 0, size);
 | |
| 				var _thumbIntermediateL = GetNewBone("Left Thumb Intermediate", _thumbProximalL, -0.05f, 0, 0, size);
 | |
| 				var _thumbIntermediateR = GetNewBone("Right Thumb Intermediate", _thumbProximalR, 0.05f, 0, 0, size);
 | |
| 				var _thumbDistalL = GetNewBone("Left Thumb Distal", _thumbIntermediateL, -0.05f, 0, 0, size);
 | |
| 				var _thumbDistalR = GetNewBone("Right Thumb Distal", _thumbIntermediateR, 0.05f, 0, 0, size);
 | |
| 
 | |
| 				var _indexProximalL = GetNewBone("Left Index Proximal", handL, -0.05f, 0, 0, size);
 | |
| 				var _indexProximalR = GetNewBone("Right Index Proximal", handR, 0.05f, 0, 0, size);
 | |
| 				var _indexIntermediateL = GetNewBone("Left Index Intermediate", _indexProximalL, -0.05f, 0, 0, size);
 | |
| 				var _indexIntermediateR = GetNewBone("Right Index Intermediate", _indexProximalR, 0.05f, 0, 0, size);
 | |
| 				var _indexDistalL = GetNewBone("Left Index Distal", _indexIntermediateL, -0.05f, 0, 0, size);
 | |
| 				var _indexDistalR = GetNewBone("Right Index Distal", _indexIntermediateR, 0.05f, 0, 0, size);
 | |
| 
 | |
| 				var _middleProximalL = GetNewBone("Left Middle Proximal", handL, -0.05f, 0, 0, size);
 | |
| 				var _middleProximalR = GetNewBone("Right Middle Proximal", handR, 0.05f, 0, 0, size);
 | |
| 				var _middleIntermediateL = GetNewBone("Left Middle Intermediate", _middleProximalL, -0.05f, 0, 0, size);
 | |
| 				var _middleIntermediateR = GetNewBone("Right Middle Intermediate", _middleProximalR, 0.05f, 0, 0, size);
 | |
| 				var _middleDistalL = GetNewBone("Left Middle Distal", _middleIntermediateL, -0.05f, 0, 0, size);
 | |
| 				var _middleDistalR = GetNewBone("Right Middle Distal", _middleIntermediateR, -0.05f, 0, 0, size);
 | |
| 
 | |
| 				var _ringProximalL = GetNewBone("Left Ring Proximal", handL, -0.05f, 0, 0, size);
 | |
| 				var _ringProximalR = GetNewBone("Right Ring Proximal", handR, 0.05f, 0, 0, size);
 | |
| 				var _ringIntermediateL = GetNewBone("Left Ring Intermediate", _ringProximalL, -0.05f, 0, 0, size);
 | |
| 				var _ringIntermediateR = GetNewBone("Right Ring Intermediate", _ringProximalR, 0.05f, 0, 0, size);
 | |
| 				var _ringDistalL = GetNewBone("Left Ring Distal", _ringIntermediateL, -0.05f, 0, 0, size);
 | |
| 				var _ringDistalR = GetNewBone("Right Ring Distal", _ringIntermediateR, -0.05f, 0, 0, size);
 | |
| 
 | |
| 				var _littleProximalL = GetNewBone("Left Little Proximal", handL, -0.05f, 0, 0, size);
 | |
| 				var _littleProximalR = GetNewBone("Right Little Proximal", handR, 0.05f, 0, 0, size);
 | |
| 				var _littleIntermediateL = GetNewBone("Left Little Intermediate", _littleProximalL, -0.05f, 0, 0, size);
 | |
| 				var _littleIntermediateR = GetNewBone("Right Little Intermediate", _littleProximalR, 0.05f, 0, 0, size);
 | |
| 				var _littleDistalL = GetNewBone("Left Little Distal", _littleIntermediateL, -0.05f, 0, 0, size);
 | |
| 				var _littleDistalR = GetNewBone("Right Little Distal", _littleIntermediateR, -0.05f, 0, 0, size);
 | |
| 
 | |
| 
 | |
| 				bones.Add(hip);
 | |
| 				bones.Add(spine);
 | |
| 				bones.Add(chest);
 | |
| 				bones.Add(neck);
 | |
| 				bones.Add(head);
 | |
| 				bones.Add(legUL);
 | |
| 				bones.Add(legUR);
 | |
| 				bones.Add(legDL);
 | |
| 				bones.Add(legDR);
 | |
| 				bones.Add(footL);
 | |
| 				bones.Add(footR);
 | |
| 				bones.Add(armUL);
 | |
| 				bones.Add(armUR);
 | |
| 				bones.Add(armDL);
 | |
| 				bones.Add(armDR);
 | |
| 				bones.Add(handL);
 | |
| 				bones.Add(handR);
 | |
| 
 | |
| 				if (fullSize) {
 | |
| 
 | |
| 					bones.Add(_upperChest);
 | |
| 					bones.Add(_eyeL);
 | |
| 					bones.Add(_eyeR);
 | |
| 					bones.Add(_jaw);
 | |
| 					bones.Add(_leftShoulder);
 | |
| 					bones.Add(_rightShoulder);
 | |
| 					bones.Add(_toeL);
 | |
| 					bones.Add(_toeR);
 | |
| 
 | |
| 
 | |
| 					bones.Add(_thumbProximalL);
 | |
| 					bones.Add(_thumbProximalR);
 | |
| 					bones.Add(_thumbIntermediateL);
 | |
| 					bones.Add(_thumbIntermediateR);
 | |
| 					bones.Add(_thumbDistalL);
 | |
| 					bones.Add(_thumbDistalR);
 | |
| 
 | |
| 					bones.Add(_indexProximalL);
 | |
| 					bones.Add(_indexProximalR);
 | |
| 					bones.Add(_indexIntermediateL);
 | |
| 					bones.Add(_indexIntermediateR);
 | |
| 					bones.Add(_indexDistalL);
 | |
| 					bones.Add(_indexDistalR);
 | |
| 
 | |
| 					bones.Add(_middleProximalL);
 | |
| 					bones.Add(_middleProximalR);
 | |
| 					bones.Add(_middleIntermediateL);
 | |
| 					bones.Add(_middleIntermediateR);
 | |
| 					bones.Add(_middleDistalL);
 | |
| 					bones.Add(_middleDistalR);
 | |
| 
 | |
| 					bones.Add(_ringProximalL);
 | |
| 					bones.Add(_ringProximalR);
 | |
| 					bones.Add(_ringIntermediateL);
 | |
| 					bones.Add(_ringIntermediateR);
 | |
| 					bones.Add(_ringDistalL);
 | |
| 					bones.Add(_ringDistalR);
 | |
| 
 | |
| 					bones.Add(_littleProximalL);
 | |
| 					bones.Add(_littleProximalR);
 | |
| 					bones.Add(_littleIntermediateL);
 | |
| 					bones.Add(_littleIntermediateR);
 | |
| 					bones.Add(_littleDistalL);
 | |
| 					bones.Add(_littleDistalR);
 | |
| 
 | |
| 				}
 | |
| 
 | |
| 				return bones;
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 
 | |
| 			public static Bone GetNewBone (string name, Bone parent, float x = 0, float y = 0, float z = 0, Vector3 size = default(Vector3)) {
 | |
| 				x *= 2f;
 | |
| 				y *= 2f;
 | |
| 				z *= 2f;
 | |
| 				return new Bone() {
 | |
| 					Name = name,
 | |
| 					Parent = parent,
 | |
| 					PositionX = x > 0 ? Mathf.CeilToInt(x * size.x) : Mathf.FloorToInt(x * size.x),
 | |
| 					PositionY = y > 0 ? Mathf.CeilToInt(y * size.y) : Mathf.FloorToInt(y * size.y),
 | |
| 					PositionZ = z > 0 ? Mathf.CeilToInt(z * size.z) : Mathf.FloorToInt(z * size.z),
 | |
| 				};
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#region --- VAR ---
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public int Version = -1;
 | |
| 		public List<int[,,]> Voxels = new List<int[,,]>();
 | |
| 		public List<Color> Palette = new List<Color>();
 | |
| 		public List<MaterialData> Materials = new List<MaterialData>();
 | |
| 		public Dictionary<int, TransformData> Transforms = new Dictionary<int, TransformData>();
 | |
| 		public Dictionary<int, GroupData> Groups = new Dictionary<int, GroupData>();
 | |
| 		public Dictionary<int, ShapeData> Shapes = new Dictionary<int, ShapeData>();
 | |
| 		public Dictionary<int, RigData> Rigs = new Dictionary<int, RigData>();
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#region --- API ---
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public Color GetColorFromPalette (int index) {
 | |
| 			index--;
 | |
| 			return index >= 0 && index < Palette.Count ? Palette[index] : Color.clear;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public Vector3 GetModelSize (int index) {
 | |
| 			return new Vector3(
 | |
| 				Voxels[index].GetLength(0),
 | |
| 				Voxels[index].GetLength(1),
 | |
| 				Voxels[index].GetLength(2)
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public Vector3 GetFootPoint (int index) {
 | |
| 
 | |
| 			var voxels = Voxels[index];
 | |
| 
 | |
| 			int sizeX = voxels.GetLength(0);
 | |
| 			int sizeY = voxels.GetLength(1);
 | |
| 			int sizeZ = voxels.GetLength(2);
 | |
| 
 | |
| 			for (int y = 0; y < sizeY; y++) {
 | |
| 				Vector3 foot = Vector3.zero;
 | |
| 				int footCount = 0;
 | |
| 				for (int x = 0; x < sizeX; x++) {
 | |
| 					for (int z = 0; z < sizeZ; z++) {
 | |
| 						var voxel = voxels[x, y, z];
 | |
| 						if (voxel != 0) {
 | |
| 							foot += new Vector3(x, y, z);
 | |
| 							footCount++;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				if (footCount > 0) {
 | |
| 					return foot / footCount;
 | |
| 				}
 | |
| 			}
 | |
| 			return Vector3.zero;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public Vector3 GetBounds () {
 | |
| 			Vector3 bounds = Vector3.zero;
 | |
| 			for (int i = 0; i < Voxels.Count; i++) {
 | |
| 				var size = GetModelSize(i);
 | |
| 				bounds = Vector3.Max(bounds, size);
 | |
| 			}
 | |
| 			return bounds;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public VoxelData GetCopy () {
 | |
| 			return new VoxelData() {
 | |
| 				Version = Version,
 | |
| 				Voxels = new List<int[,,]>(Voxels),
 | |
| 				Palette = new List<Color>(Palette),
 | |
| 				Transforms = new Dictionary<int, TransformData>(Transforms),
 | |
| 				Groups = new Dictionary<int, GroupData>(Groups),
 | |
| 				Shapes = new Dictionary<int, ShapeData>(Shapes),
 | |
| 				Materials = new List<MaterialData>(Materials),
 | |
| 				Rigs = new Dictionary<int, RigData>(Rigs),
 | |
| 			};
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public void GetModelTransform (int index, out Vector3 pos, out Vector3 rot, out Vector3 scale) {
 | |
| 			pos = Vector3.zero;
 | |
| 			rot = Vector3.zero;
 | |
| 			scale = Vector3.one;
 | |
| 			foreach (var tf in Transforms) {
 | |
| 				bool success = false;
 | |
| 				int id = tf.Value.ChildID;
 | |
| 				if (Shapes.ContainsKey(id)) {
 | |
| 					var shape = Shapes[id];
 | |
| 					for (int i = 0; i < shape.ModelData.Length; i++) {
 | |
| 						if (shape.ModelData[i].Key == index) {
 | |
| 							if (tf.Value.Frames.Length > 0) {
 | |
| 								var frame = tf.Value.Frames[0];
 | |
| 								pos = frame.Position;
 | |
| 								rot = frame.Rotation;
 | |
| 								scale = frame.Scale;
 | |
| 							}
 | |
| 							success = true;
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				if (success) {
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public Texture2D GetThumbnail (int index, bool positiveZ = true) {
 | |
| 			if (Voxels == null || index >= Voxels.Count || index < 0) { return null; }
 | |
| 			var voxels = Voxels[index];
 | |
| 			int sizeX = voxels.GetLength(0);
 | |
| 			int sizeY = voxels.GetLength(1);
 | |
| 			int sizeZ = voxels.GetLength(2);
 | |
| 			Texture2D texture = new Texture2D(sizeX, sizeY, TextureFormat.ARGB32, false);
 | |
| 			var colors = new Color[sizeX * sizeY];
 | |
| 			for (int x = 0; x < sizeX; x++) {
 | |
| 				for (int y = 0; y < sizeY; y++) {
 | |
| 					Color c = Color.clear;
 | |
| 					for (int z = positiveZ ? 0 : sizeZ - 1; positiveZ ? z < sizeZ : z >= 0; z += positiveZ ? 1 : -1) {
 | |
| 						if (voxels[x, y, z] != 0) {
 | |
| 							c = GetColorFromPalette(voxels[x, y, z]);
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 					colors[y * sizeX + (positiveZ ? x : sizeX - 1 - x)] = c;
 | |
| 				}
 | |
| 			}
 | |
| 			texture.filterMode = FilterMode.Point;
 | |
| 			texture.SetPixels(colors);
 | |
| 			texture.Apply();
 | |
| 			return texture;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public bool IsExposed (int index, int x, int y, int z, int sizeX, int sizeY, int sizeZ, Direction dir, List<MaterialData> materials = null) {
 | |
| 			return IsExposed(Voxels[index], x, y, z, sizeX, sizeY, sizeZ, dir, materials);
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public void ResetToDefaultNode () {
 | |
| 			Transforms.Clear();
 | |
| 			Groups.Clear();
 | |
| 			Shapes.Clear();
 | |
| 
 | |
| 			Transforms.Add(0, new TransformData() {
 | |
| 				ChildID = 1,
 | |
| 				Hidden = false,
 | |
| 				LayerID = -1,
 | |
| 				Name = "Root",
 | |
| 				Reserved = -1,
 | |
| 				Frames = new TransformData.FrameData[1] {
 | |
| 					new TransformData.FrameData() {
 | |
| 						Position = Vector3.zero,
 | |
| 						Rotation = Vector3.zero,
 | |
| 						Scale = Vector3.one,
 | |
| 					},
 | |
| 				},
 | |
| 			});
 | |
| 
 | |
| 			Groups.Add(1, new GroupData() {
 | |
| 				Attributes = new Dictionary<string, string>(),
 | |
| 				ChildNodeId = new int[1] { 2 },
 | |
| 			});
 | |
| 
 | |
| 			Transforms.Add(2, new TransformData() {
 | |
| 				ChildID = 3,
 | |
| 				Hidden = false,
 | |
| 				LayerID = -1,
 | |
| 				Name = "Root",
 | |
| 				Reserved = -1,
 | |
| 				Frames = new TransformData.FrameData[1] {
 | |
| 					new TransformData.FrameData() {
 | |
| 						Position = Vector3.zero,
 | |
| 						Rotation = Vector3.zero,
 | |
| 						Scale = Vector3.one,
 | |
| 					},
 | |
| 				},
 | |
| 			});
 | |
| 
 | |
| 			Shapes.Add(3, new ShapeData() {
 | |
| 				Attributes = new Dictionary<string, string>(),
 | |
| 				ModelData = new KeyValuePair<int, Dictionary<string, string>>[1] {
 | |
| 					new KeyValuePair<int, Dictionary<string, string>>(0, new Dictionary<string, string>())
 | |
| 				},
 | |
| 			});
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public void Rotate180InY () {
 | |
| 			if (Shapes.Count == 1) {
 | |
| 				for (int i = 0; i < Voxels.Count; i++) {
 | |
| 					var source = Voxels[i];
 | |
| 					int sizeX = source.GetLength(0);
 | |
| 					int sizeY = source.GetLength(1);
 | |
| 					int sizeZ = source.GetLength(2);
 | |
| 					var voxels = new int[sizeX, sizeY, sizeZ];
 | |
| 					for (int x = 0; x < sizeX; x++) {
 | |
| 						for (int y = 0; y < sizeY; y++) {
 | |
| 							for (int z = 0; z < sizeZ; z++) {
 | |
| 								voxels[x, y, z] = source[sizeX - x - 1, y, sizeZ - z - 1];
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 					Voxels[i] = voxels;
 | |
| 				}
 | |
| 			} else if (Transforms.ContainsKey(0) && Transforms[0].Frames.Length > 0) {
 | |
| 				Transforms[0].Frames[0].Rotation.y += 180;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		// Global API
 | |
| 		public static VoxelData CreateNewData () {
 | |
| 			var data = new VoxelData() {
 | |
| 				Version = 150,
 | |
| 				Materials = new List<MaterialData>(),
 | |
| 				Palette = new List<Color>() { Color.white },
 | |
| 				Rigs = new Dictionary<int, RigData>(),
 | |
| 				Voxels = new List<int[,,]>() {
 | |
| 					new int[1,1,1]{ { { 1 } } },
 | |
| 				},
 | |
| 			};
 | |
| 			data.ResetToDefaultNode();
 | |
| 			return data;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public static bool IsExposed (int[,,] voxels, int x, int y, int z, int sizeX, int sizeY, int sizeZ, Direction dir, List<MaterialData> materials = null) {
 | |
| 			bool exposed = false;
 | |
| 			if (voxels[x, y, z] != 0) {
 | |
| 				switch (dir) {
 | |
| 					case Direction.Up:
 | |
| 						exposed = y == sizeY - 1 || voxels[x, y + 1, z] == 0;
 | |
| 						break;
 | |
| 					case Direction.Down:
 | |
| 						exposed = y == 0 || voxels[x, y - 1, z] == 0;
 | |
| 						break;
 | |
| 					case Direction.Left:
 | |
| 						exposed = x == 0 || voxels[x - 1, y, z] == 0;
 | |
| 						break;
 | |
| 					case Direction.Right:
 | |
| 						exposed = x == sizeX - 1 || voxels[x + 1, y, z] == 0;
 | |
| 						break;
 | |
| 					case Direction.Front:
 | |
| 						exposed = z == sizeZ - 1 || voxels[x, y, z + 1] == 0;
 | |
| 						break;
 | |
| 					case Direction.Back:
 | |
| 						exposed = z == 0 || voxels[x, y, z - 1] == 0;
 | |
| 						break;
 | |
| 				}
 | |
| 				if (materials != null && !exposed) {
 | |
| 					int voxel = voxels[x, y, z];
 | |
| 					var material = voxel >= 0 && voxel < materials.Count ? materials[voxel] : null;
 | |
| 					if (material != null && material.Type != MaterialData.MaterialType.Glass) {
 | |
| 						int blockingVoxel = 0;
 | |
| 						switch (dir) {
 | |
| 							case Direction.Up:
 | |
| 								blockingVoxel = y == sizeY - 1 ? -1 : voxels[x, y + 1, z];
 | |
| 								break;
 | |
| 							case Direction.Down:
 | |
| 								blockingVoxel = y == 0 ? -1 : voxels[x, y - 1, z];
 | |
| 								break;
 | |
| 							case Direction.Left:
 | |
| 								blockingVoxel = x == 0 ? -1 : voxels[x - 1, y, z];
 | |
| 								break;
 | |
| 							case Direction.Right:
 | |
| 								blockingVoxel = x == sizeX - 1 ? -1 : voxels[x + 1, y, z];
 | |
| 								break;
 | |
| 							case Direction.Front:
 | |
| 								blockingVoxel = z == sizeZ - 1 ? -1 : voxels[x, y, z + 1];
 | |
| 								break;
 | |
| 							case Direction.Back:
 | |
| 								blockingVoxel = z == 0 ? -1 : voxels[x, y, z - 1];
 | |
| 								break;
 | |
| 						}
 | |
| 						var blockingMaterial = blockingVoxel >= 0 && blockingVoxel < materials.Count ? materials[blockingVoxel] : null;
 | |
| 						if (blockingMaterial != null && blockingMaterial.Type == MaterialData.MaterialType.Glass) {
 | |
| 							exposed = true;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			return exposed;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public static Material GetMaterialFrom (MaterialData mat, Texture2D texture, Shader[] shaders, string[] keywords, Vector2[] remaps, string mainTexKeyword) {
 | |
| 			if (mat == null || shaders == null || keywords == null || remaps == null) {
 | |
| 				return new Material(shaders != null && shaders.Length > 0 ? shaders[0] : Shader.Find("Mobile/Diffuse")) { mainTexture = texture };
 | |
| 			}
 | |
| 			Material material;
 | |
| 			if (shaders.Length < 5) {
 | |
| 				var shader = shaders.Length > 0 ? shaders[0] : Shader.Find("Mobile/Diffuse");
 | |
| 				shaders = new Shader[5] { shader, shader, shader, shader, shader };
 | |
| 			}
 | |
| 			switch (mat.Type) {
 | |
| 				default:
 | |
| 				case MaterialData.MaterialType.Diffuse:
 | |
| 					material = new Material(shaders[0]);
 | |
| 					break;
 | |
| 				case MaterialData.MaterialType.Metal:
 | |
| 					if (mat.Plastic == 0) {
 | |
| 						material = new Material(shaders[1]);
 | |
| 						Util.SetMaterialFloatOrColor(material, keywords[0], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[0].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[0].y, remaps[0].x, remaps[0].y, mat.Weight));// Weight
 | |
| 						Util.SetMaterialFloatOrColor(material, keywords[1], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[1].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[1].y, remaps[1].x, remaps[1].y, mat.Rough));// Rough
 | |
| 						Util.SetMaterialFloatOrColor(material, keywords[2], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[2].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[2].y, remaps[2].x, remaps[2].y, mat.Spec));// Specular
 | |
| 					} else {
 | |
| 						material = new Material(shaders[2]);
 | |
| 						Util.SetMaterialFloatOrColor(material, keywords[3], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[3].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[3].y, remaps[3].x, remaps[3].y, mat.Weight));// Weight
 | |
| 						Util.SetMaterialFloatOrColor(material, keywords[4], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[4].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[4].y, remaps[4].x, remaps[4].y, mat.Rough));// Rough
 | |
| 						Util.SetMaterialFloatOrColor(material, keywords[5], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[5].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[5].y, remaps[5].x, remaps[5].y, mat.Spec));// Specular
 | |
| 					}
 | |
| 					break;
 | |
| 				case MaterialData.MaterialType.Glass:
 | |
| 					material = new Material(shaders[3]);
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[6], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[6].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[6].y, remaps[6].x, remaps[6].y, mat.Weight));// Weight
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[7], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[7].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[7].y, remaps[7].x, remaps[7].y, mat.Rough));// Rough
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[8], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[8].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[8].y, remaps[8].x, remaps[8].y, mat.Ior));// Refract
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[9], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[9].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[9].y, remaps[9].x, remaps[9].y, mat.Att));// Att
 | |
| 					break;
 | |
| 				case MaterialData.MaterialType.Emit:
 | |
| 					material = new Material(shaders[4]);
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[10], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[10].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[10].y, remaps[10].x, remaps[10].y, mat.Weight));// Weight
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[11], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[11].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[11].y, remaps[11].x, remaps[11].y, mat.Flux));// Power
 | |
| 					Util.SetMaterialFloatOrColor(material, keywords[12], Util.Remap(MaterialData.SHADER_VALUE_REMAP_SOURCE[12].x, MaterialData.SHADER_VALUE_REMAP_SOURCE[12].y, remaps[12].x, remaps[12].y, mat.LDR));// ldr
 | |
| 					break;
 | |
| 			}
 | |
| 			material.SetTexture(mainTexKeyword, texture);
 | |
| 			return material;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public static implicit operator bool (VoxelData data) {
 | |
| 			return data != null;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public static VoxelData GetSplitedData (VoxelData source) {
 | |
| 
 | |
| 
 | |
| 			const int SPLIT_SIZE = 126;
 | |
| 			if (source.Voxels.Count == 0) {
 | |
| 				return source;
 | |
| 			}
 | |
| 
 | |
| 			var size = source.GetModelSize(0);
 | |
| 			int sizeX = Mathf.RoundToInt(size.x);
 | |
| 			int sizeY = Mathf.RoundToInt(size.y);
 | |
| 			int sizeZ = Mathf.RoundToInt(size.z);
 | |
| 			if (sizeX <= SPLIT_SIZE && sizeY <= SPLIT_SIZE && sizeZ <= SPLIT_SIZE) {
 | |
| 				return source;
 | |
| 			}
 | |
| 
 | |
| 			int splitCountX = (sizeX / SPLIT_SIZE) + 1;
 | |
| 			int splitCountY = (sizeY / SPLIT_SIZE) + 1;
 | |
| 			int splitCountZ = (sizeZ / SPLIT_SIZE) + 1;
 | |
| 
 | |
| 			var data = new VoxelData();
 | |
| 
 | |
| 			// Nodes
 | |
| 			var childNodeId = new int[splitCountX * splitCountY * splitCountZ];
 | |
| 			for (int i = 0; i < childNodeId.Length; i++) {
 | |
| 				childNodeId[i] = i * 2 + 2;
 | |
| 			}
 | |
| 
 | |
| 			data.Voxels = new List<int[,,]>();
 | |
| 			data.Transforms = new Dictionary<int, TransformData>() {
 | |
| 				{ 0, new TransformData(){
 | |
| 					Name = "",
 | |
| 					ChildID = 1,
 | |
| 					Hidden = false,
 | |
| 					LayerID = 0,
 | |
| 					Reserved = 0,
 | |
| 					Frames = new TransformData.FrameData[1]{
 | |
| 						new TransformData.FrameData(){
 | |
| 							Position = Vector3.zero,
 | |
| 							Rotation = Vector3.zero,
 | |
| 							Scale = Vector3.one,
 | |
| 						},
 | |
| 					},
 | |
| 				}},
 | |
| 			};
 | |
| 			data.Groups = new Dictionary<int, GroupData>() {
 | |
| 				{1, new GroupData(){
 | |
| 					Attributes = new Dictionary<string, string>(),
 | |
| 					ChildNodeId = childNodeId,
 | |
| 				}},
 | |
| 			};
 | |
| 			data.Shapes = new Dictionary<int, ShapeData>();
 | |
| 			data.Palette = new List<Color>(source.Palette);
 | |
| 			data.Version = source.Version;
 | |
| 
 | |
| 			int _i = 0;
 | |
| 			for (int x = 0; x < splitCountX; x++) {
 | |
| 				for (int y = 0; y < splitCountY; y++) {
 | |
| 					for (int z = 0; z < splitCountZ; z++) {
 | |
| 						int splitSizeX = x < splitCountX - 1 ? SPLIT_SIZE : (sizeX - x * SPLIT_SIZE) % SPLIT_SIZE;
 | |
| 						int splitSizeY = y < splitCountY - 1 ? SPLIT_SIZE : (sizeY - y * SPLIT_SIZE) % SPLIT_SIZE;
 | |
| 						int splitSizeZ = z < splitCountZ - 1 ? SPLIT_SIZE : (sizeZ - z * SPLIT_SIZE) % SPLIT_SIZE;
 | |
| 						int childID = childNodeId[_i];
 | |
| 						data.Transforms.Add(childID, new TransformData() {
 | |
| 							Name = "Splited_Model_" + _i,
 | |
| 							Reserved = 0,
 | |
| 							LayerID = 0,
 | |
| 							Hidden = false,
 | |
| 							ChildID = childID + 1,
 | |
| 							Frames = new TransformData.FrameData[1] {
 | |
| 								new TransformData.FrameData(){
 | |
| 									Position = new Vector3(
 | |
| 										x * SPLIT_SIZE + splitSizeX / 2,
 | |
| 										y * SPLIT_SIZE + splitSizeY / 2,
 | |
| 										z * SPLIT_SIZE + splitSizeZ / 2
 | |
| 									),
 | |
| 									Rotation = Vector3.zero,
 | |
| 									Scale = Vector3.one,
 | |
| 								},
 | |
| 							},
 | |
| 						});
 | |
| 						data.Shapes.Add(childID + 1, new ShapeData() {
 | |
| 							Attributes = new Dictionary<string, string>(),
 | |
| 							ModelData = new KeyValuePair<int, Dictionary<string, string>>[] {
 | |
| 								new KeyValuePair<int, Dictionary<string, string>>(_i, new Dictionary<string, string>()),
 | |
| 							},
 | |
| 						});
 | |
| 						_i++;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			// Split
 | |
| 			var sourceVoxels = source.Voxels[0];
 | |
| 			for (int x = 0; x < splitCountX; x++) {
 | |
| 				for (int y = 0; y < splitCountY; y++) {
 | |
| 					for (int z = 0; z < splitCountZ; z++) {
 | |
| 						int splitSizeX = x < splitCountX - 1 ? SPLIT_SIZE : (sizeX - x * SPLIT_SIZE) % SPLIT_SIZE;
 | |
| 						int splitSizeY = y < splitCountY - 1 ? SPLIT_SIZE : (sizeY - y * SPLIT_SIZE) % SPLIT_SIZE;
 | |
| 						int splitSizeZ = z < splitCountZ - 1 ? SPLIT_SIZE : (sizeZ - z * SPLIT_SIZE) % SPLIT_SIZE;
 | |
| 						var voxels = new int[splitSizeX, splitSizeY, splitSizeZ];
 | |
| 						for (int i = 0; i < splitSizeX; i++) {
 | |
| 							for (int j = 0; j < splitSizeY; j++) {
 | |
| 								for (int k = 0; k < splitSizeZ; k++) {
 | |
| 									voxels[i, j, k] = sourceVoxels[
 | |
| 										x * SPLIT_SIZE + i,
 | |
| 										y * SPLIT_SIZE + j,
 | |
| 										z * SPLIT_SIZE + k
 | |
| 									];
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 						data.Voxels.Add(voxels);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return data;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#region --- LOD ---
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public void LodIteration (int lodLevel) {
 | |
| 
 | |
| 
 | |
| 			Rigs.Clear();
 | |
| 
 | |
| 			for (int index = 0; index < Voxels.Count; index++) {
 | |
| 				var size = GetModelSize(index);
 | |
| 				int sizeX = (int)size.x;
 | |
| 				int sizeY = (int)size.y;
 | |
| 				int sizeZ = (int)size.z;
 | |
| 				int range = lodLevel + Mathf.Max(1, (sizeX + sizeY + sizeZ) / 42);
 | |
| 				bool allZero = true;
 | |
| 				int[,,] voxels = new int[sizeX, sizeY, sizeZ];
 | |
| 				int[,,] sourceVoxels = Voxels[index];
 | |
| 				for (int x = 0; x < sizeX - range; x++) {
 | |
| 					for (int y = 0; y < sizeY - range; y++) {
 | |
| 						for (int z = 0; z < sizeZ - range; z++) {
 | |
| 							if (sourceVoxels[x, y, z] == 0) { continue; }
 | |
| 							if (allZero) { allZero = false; }
 | |
| 							SetRange(
 | |
| 								ref voxels, sourceVoxels[x, y, z],
 | |
| 								Mathf.Max(0, x - range), Mathf.Min(sizeX - 1, x + range),
 | |
| 								Mathf.Max(0, y - range), Mathf.Min(sizeY - 1, y + range),
 | |
| 								Mathf.Max(0, z - range), Mathf.Min(sizeZ - 1, z + range)
 | |
| 							);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				if (allZero) {
 | |
| 					voxels[0, 0, 0] = 1;
 | |
| 				}
 | |
| 				Voxels[index] = voxels;
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		private void SetRange (ref int[,,] voxels, int v, int l, int r, int d, int u, int b, int f) {
 | |
| 			for (int x = l; x < r; x++) {
 | |
| 				for (int y = d; y < u; y++) {
 | |
| 					for (int z = b; z < f; z++) {
 | |
| 						voxels[x, y, z] = v;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public class QbData {
 | |
| 
 | |
| 
 | |
| 		public struct QbMatrix {
 | |
| 
 | |
| 			public string Name;
 | |
| 			public int SizeX, SizeY, SizeZ;
 | |
| 			public int PosX, PosY, PosZ;
 | |
| 			public int[,,] Voxels;
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public uint Version;
 | |
| 		public uint ColorFormat; // 0->RGBA 1->BGRA
 | |
| 		public uint ZAxisOrientation; // 0->Left Handed  1->Right Handed
 | |
| 		public uint Compressed; // 0->Normal  1->WithNumbers
 | |
| 		public uint NumMatrixes;
 | |
| 		public uint VisibleMask;
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public List<QbMatrix> MatrixList;
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public VoxelData GetVoxelData () {
 | |
| 			var data = new VoxelData {
 | |
| 				Version = 150,
 | |
| 				Palette = new List<Color>(),
 | |
| 				Transforms = new Dictionary<int, VoxelData.TransformData>() {
 | |
| 					{ 0, new VoxelData.TransformData(){
 | |
| 						ChildID = 1,
 | |
| 						Hidden = false,
 | |
| 						LayerID = -1,
 | |
| 						Name = "",
 | |
| 						Reserved = -1,
 | |
| 						Frames = new VoxelData.TransformData.FrameData[1] {new VoxelData.TransformData.FrameData() {
 | |
| 							 Position = Vector3.zero,
 | |
| 							 Rotation = Vector3.zero,
 | |
| 							 Scale = Vector3.one,
 | |
| 						}},
 | |
| 					}},
 | |
| 				},
 | |
| 				Shapes = new Dictionary<int, VoxelData.ShapeData>(),
 | |
| 				Groups = new Dictionary<int, VoxelData.GroupData>() {
 | |
| 					{1, new VoxelData.GroupData(){
 | |
| 						 Attributes = new Dictionary<string, string>(),
 | |
| 						 ChildNodeId = new int[MatrixList.Count],
 | |
| 					}}
 | |
| 				},
 | |
| 				Materials = new List<VoxelData.MaterialData>(),
 | |
| 				Voxels = new List<int[,,]>(),
 | |
| 			};
 | |
| 
 | |
| 			bool leftHanded = ZAxisOrientation == 0;
 | |
| 
 | |
| 			var palette = new Dictionary<Color, int>();
 | |
| 			for (int index = 0; index < MatrixList.Count; index++) {
 | |
| 
 | |
| 				var m = MatrixList[index];
 | |
| 				int[,,] voxels = new int[m.SizeX, m.SizeY, m.SizeZ];
 | |
| 
 | |
| 				for (int x = 0; x < m.SizeX; x++) {
 | |
| 					for (int y = 0; y < m.SizeY; y++) {
 | |
| 						for (int z = 0; z < m.SizeZ; z++) {
 | |
| 							int colorInt = m.Voxels[x, y, z];
 | |
| 							if (colorInt == 0) {
 | |
| 								if (leftHanded) {
 | |
| 									voxels[x, y, m.SizeZ - z - 1] = 0;
 | |
| 								} else {
 | |
| 									voxels[x, y, z] = 0;
 | |
| 								}
 | |
| 							} else {
 | |
| 								var color = GetColor(colorInt);
 | |
| 								int cIndex;
 | |
| 								if (palette.ContainsKey(color)) {
 | |
| 									cIndex = palette[color];
 | |
| 								} else {
 | |
| 									cIndex = palette.Count;
 | |
| 									palette.Add(color, cIndex);
 | |
| 									data.Palette.Add(color);
 | |
| 								}
 | |
| 								if (leftHanded) {
 | |
| 									voxels[x, y, m.SizeZ - z - 1] = cIndex + 1;
 | |
| 								} else {
 | |
| 									voxels[x, y, z] = cIndex + 1;
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				data.Voxels.Add(voxels);
 | |
| 				data.Groups[1].ChildNodeId[index] = index * 2 + 2;
 | |
| 				data.Transforms.Add(index * 2 + 2, new VoxelData.TransformData() {
 | |
| 					ChildID = index * 2 + 3,
 | |
| 					Hidden = false,
 | |
| 					LayerID = 0,
 | |
| 					Reserved = 0,
 | |
| 					Name = "",
 | |
| 					Frames = new VoxelData.TransformData.FrameData[1] {new VoxelData.TransformData.FrameData() {
 | |
| 						Position = leftHanded ?
 | |
| 							new Vector3(m.PosX + m.SizeX / 2, m.PosY + m.SizeY / 2, -(m.PosZ + Mathf.CeilToInt(m.SizeZ / 2f))) :
 | |
| 							new Vector3(m.PosX + m.SizeX / 2, m.PosY + m.SizeY / 2, m.PosZ + m.SizeZ / 2),
 | |
| 						Rotation = Vector3.zero,
 | |
| 						Scale = Vector3.one,
 | |
| 					}},
 | |
| 				});
 | |
| 				data.Shapes.Add(index * 2 + 3, new VoxelData.ShapeData() {
 | |
| 					Attributes = new Dictionary<string, string>(),
 | |
| 					ModelData = new KeyValuePair<int, Dictionary<string, string>>[1] {
 | |
| 						new KeyValuePair<int, Dictionary<string, string>>(index, new Dictionary<string, string>())
 | |
| 					},
 | |
| 				});
 | |
| 			}
 | |
| 
 | |
| 			return data;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		private Color GetColor (int color) {
 | |
| 			if (ColorFormat == 0) {
 | |
| 				int r = 0xFF & color;
 | |
| 				int g = 0xFF00 & color;
 | |
| 				g >>= 8;
 | |
| 				int b = 0xFF0000 & color;
 | |
| 				b >>= 16;
 | |
| 				return new Color(r / 255f, g / 255f, b / 255f, 1f);
 | |
| 			} else {
 | |
| 				int b = 0xFF & color;
 | |
| 				int g = 0xFF00 & color;
 | |
| 				g >>= 8;
 | |
| 				int r = 0xFF0000 & color;
 | |
| 				r >>= 16;
 | |
| 				return new Color(r / 255f, g / 255f, b / 255f, 1f);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 	[System.Serializable]
 | |
| 	public class VoxelJsonData {
 | |
| 
 | |
| 
 | |
| 		[System.Serializable]
 | |
| 		public class IntArray3 {
 | |
| 			public int[] Value;
 | |
| 			public int SizeX;
 | |
| 			public int SizeY;
 | |
| 			public int SizeZ;
 | |
| 
 | |
| 			public IntArray3 (int sizeX, int sizeY, int sizeZ) {
 | |
| 				SizeX = sizeX;
 | |
| 				SizeY = sizeY;
 | |
| 				SizeZ = sizeZ;
 | |
| 				Value = new int[sizeX * sizeY * sizeZ];
 | |
| 			}
 | |
| 
 | |
| 			public void Set (int x, int y, int z, int value) {
 | |
| 				Value[z * SizeX * SizeY + y * SizeX + x] = value;
 | |
| 			}
 | |
| 
 | |
| 			public int Get (int x, int y, int z) {
 | |
| 				return Value[z * SizeX * SizeY + y * SizeX + x];
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		[System.Serializable]
 | |
| 		public class SerGroupData {
 | |
| 			public int Index;
 | |
| 			public string[] AttKeys;
 | |
| 			public string[] Attributes;
 | |
| 			public int[] ChildNodeId;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		[System.Serializable]
 | |
| 		public class SerShapeData {
 | |
| 
 | |
| 			[System.Serializable]
 | |
| 			public class ModelMap {
 | |
| 				public string[] Key;
 | |
| 				public string[] Value;
 | |
| 			}
 | |
| 
 | |
| 			public int Index;
 | |
| 			public string[] AttKeys;
 | |
| 			public string[] Attributes;
 | |
| 			public int[] ModelDataIndexs;
 | |
| 			public ModelMap[] ModelDatas;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public int Version;
 | |
| 		public IntArray3[] Voxels;
 | |
| 		public Color[] Palette;
 | |
| 		public VoxelData.MaterialData[] Materials;
 | |
| 		public int[] TransformIndexs;
 | |
| 		public VoxelData.TransformData[] Transforms;
 | |
| 		public SerGroupData[] Groups;
 | |
| 		public SerShapeData[] Shapes;
 | |
| 		public int[] RigIndexs;
 | |
| 		public VoxelData.RigData[] Rigs;
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public VoxelJsonData (VoxelData source) {
 | |
| 
 | |
| 			// Version
 | |
| 			Version = source.Version;
 | |
| 
 | |
| 			// Voxels
 | |
| 			Voxels = new IntArray3[source.Voxels.Count];
 | |
| 			for (int i = 0; i < Voxels.Length; i++) {
 | |
| 				int sizeX = source.Voxels[i].GetLength(0);
 | |
| 				int sizeY = source.Voxels[i].GetLength(1);
 | |
| 				int sizeZ = source.Voxels[i].GetLength(2);
 | |
| 				var voxels = new IntArray3(sizeX, sizeY, sizeZ);
 | |
| 				var sourceVoxels = source.Voxels[i];
 | |
| 				for (int x = 0; x < sizeX; x++) {
 | |
| 					for (int y = 0; y < sizeY; y++) {
 | |
| 						for (int z = 0; z < sizeZ; z++) {
 | |
| 							voxels.Set(x, y, z, sourceVoxels[x, y, z]);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				Voxels[i] = voxels;
 | |
| 			}
 | |
| 
 | |
| 			// Palette
 | |
| 			Palette = source.Palette.ToArray();
 | |
| 
 | |
| 			// Materials
 | |
| 			Materials = source.Materials.ToArray();
 | |
| 
 | |
| 			// Transforms
 | |
| 			var tfMap = source.Transforms;
 | |
| 			TransformIndexs = new int[tfMap.Count];
 | |
| 			Transforms = new VoxelData.TransformData[tfMap.Count];
 | |
| 			int index = 0;
 | |
| 			foreach (var tf in tfMap) {
 | |
| 				TransformIndexs[index] = tf.Key;
 | |
| 				Transforms[index] = tf.Value;
 | |
| 				index++;
 | |
| 			}
 | |
| 
 | |
| 			// Groups
 | |
| 			var gpMap = source.Groups;
 | |
| 			Groups = new SerGroupData[gpMap.Count];
 | |
| 			index = 0;
 | |
| 			foreach (var gp in gpMap) {
 | |
| 				Groups[index] = new SerGroupData() {
 | |
| 					Index = gp.Key,
 | |
| 					ChildNodeId = gp.Value.ChildNodeId,
 | |
| 					AttKeys = new string[gp.Value.Attributes.Count],
 | |
| 					Attributes = new string[gp.Value.Attributes.Count],
 | |
| 				};
 | |
| 				var attMap = gp.Value.Attributes;
 | |
| 				int i = 0;
 | |
| 				foreach (var att in attMap) {
 | |
| 					Groups[index].AttKeys[i] = att.Key;
 | |
| 					Groups[index].Attributes[i] = att.Value;
 | |
| 					i++;
 | |
| 				}
 | |
| 				index++;
 | |
| 			}
 | |
| 
 | |
| 			// Shapes
 | |
| 			var shMap = source.Shapes;
 | |
| 			Shapes = new SerShapeData[shMap.Count];
 | |
| 			index = 0;
 | |
| 			foreach (var sh in shMap) {
 | |
| 				Shapes[index] = new SerShapeData {
 | |
| 					Index = sh.Key,
 | |
| 					ModelDataIndexs = new int[sh.Value.ModelData.Length],
 | |
| 					ModelDatas = new SerShapeData.ModelMap[sh.Value.ModelData.Length],
 | |
| 					AttKeys = new string[sh.Value.Attributes.Count],
 | |
| 					Attributes = new string[sh.Value.Attributes.Count],
 | |
| 				};
 | |
| 				var attMap = sh.Value.Attributes;
 | |
| 				int i = 0;
 | |
| 				foreach (var att in attMap) {
 | |
| 					Shapes[index].AttKeys[i] = att.Key;
 | |
| 					Shapes[index].Attributes[i] = att.Value;
 | |
| 					i++;
 | |
| 				}
 | |
| 				for (i = 0; i < sh.Value.ModelData.Length; i++) {
 | |
| 					Shapes[index].ModelDataIndexs[i] = sh.Value.ModelData[i].Key;
 | |
| 					Shapes[index].ModelDatas[i] = new SerShapeData.ModelMap() {
 | |
| 						Key = new string[sh.Value.ModelData[i].Value.Count],
 | |
| 						Value = new string[sh.Value.ModelData[i].Value.Count],
 | |
| 					};
 | |
| 					int j = 0;
 | |
| 					var map = sh.Value.ModelData[i].Value;
 | |
| 					foreach (var aj in map) {
 | |
| 						Shapes[index].ModelDatas[i].Key[j] = aj.Key;
 | |
| 						Shapes[index].ModelDatas[i].Value[j] = aj.Value;
 | |
| 						j++;
 | |
| 					}
 | |
| 				}
 | |
| 				index++;
 | |
| 			}
 | |
| 
 | |
| 			// Rigs
 | |
| 			var rigMap = source.Rigs;
 | |
| 			RigIndexs = new int[rigMap.Count];
 | |
| 			Rigs = new VoxelData.RigData[rigMap.Count];
 | |
| 			index = 0;
 | |
| 			foreach (var rig in rigMap) {
 | |
| 				RigIndexs[index] = rig.Key;
 | |
| 				Rigs[index] = rig.Value;
 | |
| 				var bones = Rigs[index].Bones;
 | |
| 				for (int i = 0; i < bones.Count; i++) {
 | |
| 					bones[i].ParentIndex = bones.IndexOf(bones[i].Parent);
 | |
| 				}
 | |
| 				index++;
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public VoxelData GetVoxelData () {
 | |
| 
 | |
| 			var data = new VoxelData() {
 | |
| 				Version = Version,
 | |
| 				Voxels = new List<int[,,]>(),
 | |
| 				Palette = new List<Color>(Palette),
 | |
| 				Materials = new List<VoxelData.MaterialData>(Materials),
 | |
| 				Transforms = new Dictionary<int, VoxelData.TransformData>(),
 | |
| 				Groups = new Dictionary<int, VoxelData.GroupData>(),
 | |
| 				Shapes = new Dictionary<int, VoxelData.ShapeData>(),
 | |
| 				Rigs = new Dictionary<int, VoxelData.RigData>(),
 | |
| 			};
 | |
| 
 | |
| 			// Voxels
 | |
| 			for (int i = 0; i < Voxels.Length; i++) {
 | |
| 				var sourceV = Voxels[i];
 | |
| 				int[,,] vs = new int[sourceV.SizeX, sourceV.SizeY, sourceV.SizeZ];
 | |
| 				for (int x = 0; x < sourceV.SizeX; x++) {
 | |
| 					for (int y = 0; y < sourceV.SizeY; y++) {
 | |
| 						for (int z = 0; z < sourceV.SizeZ; z++) {
 | |
| 							vs[x, y, z] = sourceV.Get(x, y, z);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				data.Voxels.Add(vs);
 | |
| 			}
 | |
| 
 | |
| 			// Transforms
 | |
| 			for (int i = 0; i < Transforms.Length; i++) {
 | |
| 				data.Transforms.Add(TransformIndexs[i], Transforms[i]);
 | |
| 			}
 | |
| 
 | |
| 			// Groups
 | |
| 			for (int i = 0; i < Groups.Length; i++) {
 | |
| 				var groupData = new VoxelData.GroupData() {
 | |
| 					ChildNodeId = Groups[i].ChildNodeId,
 | |
| 					Attributes = new Dictionary<string, string>(),
 | |
| 				};
 | |
| 				for (int j = 0; j < Groups[i].AttKeys.Length; j++) {
 | |
| 					groupData.Attributes.Add(Groups[i].AttKeys[j], Groups[i].Attributes[j]);
 | |
| 				}
 | |
| 				data.Groups.Add(Groups[i].Index, groupData);
 | |
| 			}
 | |
| 
 | |
| 			// Shapes
 | |
| 			for (int i = 0; i < Shapes.Length; i++) {
 | |
| 				var sourceShape = Shapes[i];
 | |
| 				var shapeData = new VoxelData.ShapeData() {
 | |
| 					Attributes = new Dictionary<string, string>(),
 | |
| 					ModelData = new KeyValuePair<int, Dictionary<string, string>>[sourceShape.ModelDatas.Length],
 | |
| 				};
 | |
| 				for (int j = 0; j < sourceShape.Attributes.Length; j++) {
 | |
| 					shapeData.Attributes.Add(sourceShape.AttKeys[j], sourceShape.Attributes[j]);
 | |
| 				}
 | |
| 				for (int j = 0; j < sourceShape.ModelDatas.Length; j++) {
 | |
| 					shapeData.ModelData[j] = new KeyValuePair<int, Dictionary<string, string>>(
 | |
| 						sourceShape.ModelDataIndexs[j],
 | |
| 						new Dictionary<string, string>()
 | |
| 					);
 | |
| 					var sourceData = sourceShape.ModelDatas[j];
 | |
| 					for (int k = 0; k < sourceData.Value.Length; k++) {
 | |
| 						shapeData.ModelData[j].Value.Add(sourceData.Key[k], sourceData.Value[k]);
 | |
| 					}
 | |
| 				}
 | |
| 				data.Shapes.Add(sourceShape.Index, shapeData);
 | |
| 			}
 | |
| 
 | |
| 			// Rig
 | |
| 			for (int i = 0; i < Rigs.Length; i++) {
 | |
| 				var bones = Rigs[i].Bones;
 | |
| 				for (int j = 0; j < bones.Count; j++) {
 | |
| 					bones[j].Parent = null;
 | |
| 					int pIndex = bones[j].ParentIndex;
 | |
| 					if (pIndex >= 0 && pIndex < bones.Count) {
 | |
| 						bones[j].Parent = bones[pIndex];
 | |
| 					}
 | |
| 				}
 | |
| 				data.Rigs.Add(RigIndexs[i], Rigs[i]);
 | |
| 			}
 | |
| 
 | |
| 			return data;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| } |