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;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} |