using UnityEngine;
using System.Collections.Generic;
using System;
using System.Runtime.CompilerServices;
namespace UMA
{
///
/// Base class for serializing recipes as "packed" int/byte based data.
///
public abstract class UMAPackedRecipeBase : UMARecipeBase
{
///
/// Load data into the specified UMA recipe.
///
/// UMA recipe.
/// Context.
public override void Load(UMA.UMAData.UMARecipe umaRecipe, UMAContextBase context)
{
var packedRecipe = PackedLoad(context);
UnpackRecipe(umaRecipe, packedRecipe, context);
}
public static UMAData.UMARecipe UnpackRecipe(UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
UMAData.UMARecipe umaRecipe = new UMAData.UMARecipe();
UnpackRecipe(umaRecipe, umaPackRecipe, context);
return umaRecipe;
}
public static void UnpackRecipe(UMA.UMAData.UMARecipe umaRecipe, UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
switch (umaPackRecipe.version)
{
case 3:
UnpackRecipeVersion3(umaRecipe, umaPackRecipe, context);
break;
case 2:
UnpackRecipeVersion2(umaRecipe, umaPackRecipe, context);
break;
case 1:
default:
if (UnpackRecipeVersion1(umaRecipe, umaPackRecipe, context))
{
umaRecipe.MergeMatchingOverlays();
}
break;
}
}
///
/// Save data from the specified UMA recipe.
///
/// UMA recipe.
/// Context.
public override void Save(UMA.UMAData.UMARecipe umaRecipe, UMAContextBase context)
{
umaRecipe.MergeMatchingOverlays();
var packedRecipe = PackRecipeV3(umaRecipe);
PackedSave(packedRecipe, context);
}
///
/// Load serialized data into the packed recipe.
///
/// The UMAPackRecipe.
/// Context.
public abstract UMAPackRecipe PackedLoad(UMAContextBase context);
///
/// Serialize the packed recipe.
///
/// Packed recipe.
/// Context.
public abstract void PackedSave(UMAPackRecipe packedRecipe, UMAContextBase context);
#region Packing Related
[System.Serializable]
public class packedSlotData
{
public string slotID;
public int overlayScale = 1;
public int copyOverlayIndex = -1;
public packedOverlayData[] OverlayDataList;
}
[System.Serializable]
public class packedOverlayData
{
public string overlayID;
public int[] colorList;
public int[][] channelMaskList;
public int[][] channelAdditiveMaskList;
public int[] rectList;
}
[System.Serializable]
public class PackedSlotDataV2
{
public string id;
public int scale = 1;
public int copyIdx = -1;
public PackedOverlayDataV2[] overlays;
}
[System.Serializable]
public class PackedOverlayDataV2
{
public string id;
public int colorIdx;
public int[] rect;
}
[System.Serializable]
public class PackedOverlayColorDataV2
{
public string name;
public byte[] color;
public byte[][] masks;
public byte[][] addMasks;
public PackedOverlayColorDataV2()
{
name = "";
color = new byte[4];
}
public PackedOverlayColorDataV2(OverlayColorData colorData)
{
name = colorData.name;
color = new byte[4];
color[0] = (byte)Mathf.FloorToInt(colorData.color.r * 255f);
color[1] = (byte)Mathf.FloorToInt(colorData.color.g * 255f);
color[2] = (byte)Mathf.FloorToInt(colorData.color.b * 255f);
color[3] = (byte)Mathf.FloorToInt(colorData.color.a * 255f);
if (UMAPackRecipe.ArrayHasData(colorData.channelMask))
{
int channelCount = colorData.channelMask.Length;
masks = new byte[channelCount][];
addMasks = new byte[channelCount][];
for (int channel = 0; channel < channelCount; channel++)
{
masks[channel] = new byte[4];
addMasks[channel] = new byte[4];
Color32 maskColor = colorData.channelMask[channel];
masks[channel][0] = maskColor.r;
masks[channel][1] = maskColor.g;
masks[channel][2] = maskColor.b;
masks[channel][3] = maskColor.a;
Color32 additiveMaskColor = colorData.channelAdditiveMask[channel];
addMasks[channel][0] = additiveMaskColor.r;
addMasks[channel][1] = additiveMaskColor.g;
addMasks[channel][2] = additiveMaskColor.b;
addMasks[channel][3] = additiveMaskColor.a;
}
}
}
public void SetOverlayColorData(OverlayColorData overlayColorData)
{
overlayColorData.name = name;
if (UMAPackRecipe.ArrayHasData(masks))
{
int channelCount = masks.Length;
overlayColorData.channelMask = new Color[channelCount];
overlayColorData.channelAdditiveMask = new Color[channelCount];
for (int channel = 0; channel < channelCount; channel++)
{
overlayColorData.channelMask[channel].r = masks[channel][0] / 255f;
overlayColorData.channelMask[channel].g = masks[channel][1] / 255f;
overlayColorData.channelMask[channel].b = masks[channel][2] / 255f;
overlayColorData.channelMask[channel].a = masks[channel][3] / 255f;
overlayColorData.channelAdditiveMask[channel].r = addMasks[channel][0];
overlayColorData.channelAdditiveMask[channel].g = addMasks[channel][1];
overlayColorData.channelAdditiveMask[channel].b = addMasks[channel][2];
overlayColorData.channelAdditiveMask[channel].a = addMasks[channel][3];
}
}
else
{
overlayColorData.channelMask = new Color[1];
overlayColorData.channelAdditiveMask = new Color[1];
overlayColorData.channelMask[0] = new Color(color[0] / 255f, color[1] / 255f, color[2] / 255f, color[3] / 255f);
}
}
}
[System.Serializable]
public class PackedSlotDataV3
{
public string id;
public int scale = 1;
public int copyIdx = -1;
public PackedOverlayDataV3[] overlays;
public string[] Tags; // Any recipe specific tags.
public string[] Races;
public string blendShapeTarget;
public float overSmoosh;
public float smooshDistance;
public bool smooshInvertX;
public bool smooshInvertY;
public bool smooshInvertZ;
public bool smooshInvertDist;
public string smooshTargetTag;
public string smooshableTag;
public bool isSwapSlot;
public string swapTag;
public int uvOverride;
public bool isDisabled;
public int expandAlongNormal; // Fixed point expansion along normals. divided by 10,000,000
}
[System.Serializable]
public class PackedOverlayDataV3
{
public string id;
public int colorIdx;
// public int[] rect;
public float[] rect;
public bool isTransformed;
public Vector3 scale;
public float rotation;
public int[] blendModes;
public string[] Tags; // Any recipe specific tags.
public bool[] tiling;
public int uvOverride;
}
#if (UNITY_STANDALONE || UNITY_IOS || UNITY_ANDROID || UNITY_PS4 || UNITY_XBOXONE) && !UNITY_2017_3_OR_NEWER //supported platforms for procedural materials
[System.Serializable]
public class PackedOverlaySubstanceData
{
const float floatIntScale = 1024f;
const float intFloatScale = 1f / floatIntScale;
public string name;
public int type;
public int[] vals;
public string text;
public PackedOverlaySubstanceData(OverlayData.OverlayProceduralData proceduralData)
{
this.name = proceduralData.name;
this.type = (int)proceduralData.type;
switch (proceduralData.type)
{
case ProceduralPropertyType.Boolean:
vals = new int[1];
vals[0] = proceduralData.booleanValue ? 1 : 0;
break;
case ProceduralPropertyType.Color3:
vals = new int[3];
Color32 color3 = proceduralData.colorValue;
vals[0] = color3.r;
vals[1] = color3.g;
vals[2] = color3.b;
break;
case ProceduralPropertyType.Color4:
vals = new int[4];
Color32 color4 = proceduralData.colorValue;
vals[0] = color4.r;
vals[1] = color4.g;
vals[2] = color4.b;
vals[3] = color4.a;
break;
case ProceduralPropertyType.Enum:
vals = new int[1];
vals[0] = proceduralData.enumValue;
break;
case ProceduralPropertyType.Float:
vals = new int[1];
vals[0] = Mathf.FloorToInt(proceduralData.floatValue * floatIntScale);
break;
case ProceduralPropertyType.Vector2:
vals = new int[2];
vals[0] = Mathf.FloorToInt(proceduralData.vectorValue.x * floatIntScale);
vals[1] = Mathf.FloorToInt(proceduralData.vectorValue.y * floatIntScale);
break;
case ProceduralPropertyType.Vector3:
vals = new int[3];
vals[0] = Mathf.FloorToInt(proceduralData.vectorValue.x * floatIntScale);
vals[1] = Mathf.FloorToInt(proceduralData.vectorValue.y * floatIntScale);
vals[2] = Mathf.FloorToInt(proceduralData.vectorValue.z * floatIntScale);
break;
case ProceduralPropertyType.Vector4:
vals = new int[4];
vals[0] = Mathf.FloorToInt(proceduralData.vectorValue.x * floatIntScale);
vals[1] = Mathf.FloorToInt(proceduralData.vectorValue.y * floatIntScale);
vals[2] = Mathf.FloorToInt(proceduralData.vectorValue.z * floatIntScale);
vals[3] = Mathf.FloorToInt(proceduralData.vectorValue.w * floatIntScale);
break;
case ProceduralPropertyType.Texture:
if (Debug.isDebugBuild)
Debug.LogWarning("Unsupported Texture property on OverlayProceduralData.");
break;
default:
if (Debug.isDebugBuild)
Debug.LogError("Unsupported type enum in OverlayProceduralData! " + proceduralData.type);
break;
}
}
public void SetOverlayProceduralData(OverlayData.OverlayProceduralData proceduralData)
{
proceduralData.name = this.name;
switch (this.type)
{
case (int)ProceduralPropertyType.Boolean:
proceduralData.type = ProceduralPropertyType.Boolean;
proceduralData.booleanValue = this.vals[0] > 0;
break;
case (int)ProceduralPropertyType.Color3:
proceduralData.type = ProceduralPropertyType.Color3;
proceduralData.colorValue = new Color32((byte)this.vals[0], (byte)this.vals[1], (byte)this.vals[2], 255);
break;
case (int)ProceduralPropertyType.Color4:
proceduralData.type = ProceduralPropertyType.Color4;
proceduralData.colorValue = new Color32((byte)this.vals[0], (byte)this.vals[1], (byte)this.vals[2], (byte)this.vals[3]);
break;
case (int)ProceduralPropertyType.Enum:
proceduralData.type = ProceduralPropertyType.Enum;
proceduralData.enumValue = this.vals[0];
break;
case (int)ProceduralPropertyType.Float:
proceduralData.type = ProceduralPropertyType.Float;
proceduralData.floatValue = intFloatScale * this.vals[0];
break;
case (int)ProceduralPropertyType.Vector2:
proceduralData.type = ProceduralPropertyType.Vector2;
proceduralData.vectorValue.x = intFloatScale * this.vals[0];
proceduralData.vectorValue.y = intFloatScale * this.vals[1];
break;
case (int)ProceduralPropertyType.Vector3:
proceduralData.type = ProceduralPropertyType.Vector3;
proceduralData.vectorValue.x = intFloatScale * this.vals[0];
proceduralData.vectorValue.y = intFloatScale * this.vals[1];
proceduralData.vectorValue.z = intFloatScale * this.vals[2];
break;
case (int)ProceduralPropertyType.Vector4:
proceduralData.type = ProceduralPropertyType.Vector4;
proceduralData.vectorValue.x = intFloatScale * this.vals[0];
proceduralData.vectorValue.y = intFloatScale * this.vals[1];
proceduralData.vectorValue.z = intFloatScale * this.vals[2];
proceduralData.vectorValue.w = intFloatScale * this.vals[3];
break;
case (int)ProceduralPropertyType.Texture:
proceduralData.type = ProceduralPropertyType.Texture;
if (Debug.isDebugBuild)
Debug.LogWarning("Unsupported Texture property in PackedOverlaySubstanceData.");
break;
default:
if (Debug.isDebugBuild)
Debug.LogError("Bad type enum in PackedOverlaySubstanceData! " + this.type);
break;
}
}
}
#endif
[System.Serializable]
public class PackedOverlayColorDataV3
{
public string name;
// Put everything in one array
public short[] colors;
public string[] ShaderParms;
public bool alwaysUpdate;
public bool alwaysUpdateParms;
public bool isBaseColor;
public int displayColor;
public PackedOverlayColorDataV3()
{
name = "";
colors = new short[0];
ShaderParms = new string[0];
#if UNITY_EDITOR
alwaysUpdate = false;
isBaseColor = false;
#endif
}
public PackedOverlayColorDataV3(OverlayColorData colorData)
{
name = colorData.name;
if (UMAPackRecipe.ArrayHasData(colorData.channelMask))
{
int channelCount = colorData.channelMask.Length;
colors = new short[channelCount * 8];
int colorIndex = 0;
for (int channel = 0; channel < channelCount; channel++)
{
Color maskColor = colorData.channelMask[channel];
colors[colorIndex++] = (short)Mathf.FloorToInt(maskColor.r * 255f);
colors[colorIndex++] = (short)Mathf.FloorToInt(maskColor.g * 255f);
colors[colorIndex++] = (short)Mathf.FloorToInt(maskColor.b * 255f);
colors[colorIndex++] = (short)Mathf.FloorToInt(maskColor.a * 255f);
Color additiveMaskColor = colorData.channelAdditiveMask[channel];
colors[colorIndex++] = (short)Mathf.FloorToInt(additiveMaskColor.r * 255f);
colors[colorIndex++] = (short)Mathf.FloorToInt(additiveMaskColor.g * 255f);
colors[colorIndex++] = (short)Mathf.FloorToInt(additiveMaskColor.b * 255f);
colors[colorIndex++] = (short)Mathf.FloorToInt(additiveMaskColor.a * 255f);
}
}
Color32 color32 = colorData.color;
displayColor = color32.r | (color32.g << 8) | (color32.b << 16) | (color32.a << 24);
if (colorData.HasPropertyBlock)
{
alwaysUpdate = colorData.PropertyBlock.alwaysUpdate;
alwaysUpdateParms = colorData.PropertyBlock.alwaysUpdateParms;
}
#if UNITY_EDITOR
isBaseColor = colorData.isBaseColor;
#endif
if (colorData.HasProperties)
{
ShaderParms = new string[colorData.PropertyBlock.shaderProperties.Count];
for (int i= 0; i < colorData.PropertyBlock.shaderProperties.Count; i++)
{
UMAProperty up = colorData.PropertyBlock.shaderProperties[i];
if (up != null)
{
ShaderParms[i] = up.ToString();
}
}
}
}
public void SetOverlayColorData(OverlayColorData overlayColorData)
{
overlayColorData.name = name;
if (UMAPackRecipe.ArrayHasData(colors))
{
int channelCount = colors.Length / 8;
overlayColorData.channelMask = new Color[channelCount];
overlayColorData.channelAdditiveMask = new Color[channelCount];
overlayColorData.displayColor = new Color32((byte)(displayColor & 0xFF), (byte)((displayColor >> 8) & 0xFF), (byte)((displayColor >> 16) & 0xFF), (byte)((displayColor >> 24) & 0xFF));
#if UNITY_EDITOR
overlayColorData.isBaseColor = isBaseColor;
#endif
int colorIndex = 0;
for (int channel = 0; channel < channelCount; channel++)
{
overlayColorData.channelMask[channel].r = colors[colorIndex++] / 255f;
overlayColorData.channelMask[channel].g = colors[colorIndex++] / 255f;
overlayColorData.channelMask[channel].b = colors[colorIndex++] / 255f;
overlayColorData.channelMask[channel].a = colors[colorIndex++] / 255f;
overlayColorData.channelAdditiveMask[channel].r = colors[colorIndex++] / 255f;
overlayColorData.channelAdditiveMask[channel].g = colors[colorIndex++] / 255f;
overlayColorData.channelAdditiveMask[channel].b = colors[colorIndex++] / 255f;
overlayColorData.channelAdditiveMask[channel].a = colors[colorIndex++] / 255f;
}
overlayColorData.PropertyBlock = null;
if (ShaderParms.Length > 0)
{
overlayColorData.PropertyBlock = new UMAMaterialPropertyBlock();
overlayColorData.PropertyBlock.alwaysUpdate = alwaysUpdate;
overlayColorData.PropertyBlock.alwaysUpdateParms = alwaysUpdateParms;
for(int i=0;i umaDna = new Dictionary();
public List packedDna = new List();
public int uvOverride = 0;
public static bool ArrayHasData(Array array)
{
return array != null && array.Length > 0;
}
public static bool SlotIsValid(SlotData slotData)
{
return slotData != null && slotData.asset != null && !string.IsNullOrEmpty(slotData.asset.slotName);
}
public static bool SlotIsValid(packedSlotData packedSlotData)
{
return packedSlotData != null && !string.IsNullOrEmpty(packedSlotData.slotID);
}
public static bool SlotIsValid(PackedSlotDataV2 packedSlot)
{
return packedSlot != null && !string.IsNullOrEmpty(packedSlot.id);
}
public static bool SlotIsValid(PackedSlotDataV3 packedSlot)
{
return packedSlot != null && !string.IsNullOrEmpty(packedSlot.id);
}
public static bool MaterialIsValid(UMAMaterial material)
{
return material != null && !string.IsNullOrEmpty(material.name);
}
public static bool RaceIsValid(RaceData raceData)
{
return raceData != null && !string.IsNullOrEmpty(raceData.raceName);
}
}
public static List GetPackedDNA(UMAData.UMARecipe umaRecipe)
{
List PackedDNAlist = new List();
UMADnaBase[] array = umaRecipe.GetAllDna();
for (int i = 0; i < array.Length; i++)
{
UMADnaBase dna = array[i];
UMAPackedDna packedDna = new UMAPackedDna();
//DynamicUMADna:: needs the typeHash as this is randomly generated by the DynamicDnaConverter
packedDna.dnaTypeHash = dna.DNATypeHash;
packedDna.dnaType = dna.GetType().Name;
packedDna.packedDna = UMA.UMADna.SaveInstance(dna);
PackedDNAlist.Add(packedDna);
}
return PackedDNAlist;
}
public static UMAPackRecipe PackRecipeV3(UMA.UMAData.UMARecipe umaRecipe)
{
UMAPackRecipe umaPackRecipe = new UMAPackRecipe();
umaPackRecipe.version = 3;
int slotCount = umaRecipe.slotDataList.Length;
umaPackRecipe.slotsV3 = new PackedSlotDataV3[slotCount];
if (UMAPackRecipe.RaceIsValid(umaRecipe.raceData))
{
umaPackRecipe.race = umaRecipe.raceData.raceName;
}
umaPackRecipe.packedDna = GetPackedDNA(umaRecipe);
umaPackRecipe.sharedColorCount = 0;
if (UMAPackRecipe.ArrayHasData(umaRecipe.sharedColors))
{
umaPackRecipe.sharedColorCount = umaRecipe.sharedColors.Length;
}
List colorEntries = new List(umaPackRecipe.sharedColorCount);
List packedColorEntries = new List(umaPackRecipe.sharedColorCount);
for (int i = 0; i < umaPackRecipe.sharedColorCount; i++)
{
colorEntries.Add(umaRecipe.sharedColors[i]);
packedColorEntries.Add(new PackedOverlayColorDataV3(umaRecipe.sharedColors[i]));
}
for (int i = 0; i < slotCount; i++)
{
if (UMAPackRecipe.SlotIsValid(umaRecipe.slotDataList[i]) && !umaRecipe.slotDataList[i].dontSerialize)
{
PackedSlotDataV3 tempPackedSlotData = new PackedSlotDataV3();
umaPackRecipe.slotsV3[i] = tempPackedSlotData;
tempPackedSlotData.id = umaRecipe.slotDataList[i].asset.slotName;
tempPackedSlotData.scale = Mathf.FloorToInt(umaRecipe.slotDataList[i].overlayScale * 100);
tempPackedSlotData.Tags = umaRecipe.slotDataList[i].tags.Clone() as string[];
tempPackedSlotData.Races = umaRecipe.slotDataList[i].Races;
tempPackedSlotData.blendShapeTarget = umaRecipe.slotDataList[i].blendShapeTargetSlot;
tempPackedSlotData.overSmoosh = umaRecipe.slotDataList[i].overSmoosh;
tempPackedSlotData.smooshDistance = umaRecipe.slotDataList[i].smooshDistance;
tempPackedSlotData.smooshInvertDist = umaRecipe.slotDataList[i].smooshInvertDist;
tempPackedSlotData.smooshInvertX = umaRecipe.slotDataList[i].smooshInvertX;
tempPackedSlotData.smooshInvertY = umaRecipe.slotDataList[i].smooshInvertY;
tempPackedSlotData.smooshInvertZ = umaRecipe.slotDataList[i].smooshInvertZ;
tempPackedSlotData.smooshableTag = umaRecipe.slotDataList[i].smooshableTag;
tempPackedSlotData.smooshTargetTag = umaRecipe.slotDataList[i].smooshTargetTag;
tempPackedSlotData.swapTag = umaRecipe.slotDataList[i].swapTag;
tempPackedSlotData.isSwapSlot = umaRecipe.slotDataList[i].isSwapSlot;
tempPackedSlotData.uvOverride = umaRecipe.slotDataList[i].UVSet;
tempPackedSlotData.isDisabled = umaRecipe.slotDataList[i].isDisabled;
tempPackedSlotData.expandAlongNormal = umaRecipe.slotDataList[i].expandAlongNormal;
bool copiedOverlays = false;
for (int i2 = 0; i2 < i; i2++)
{
if (UMAPackRecipe.SlotIsValid(umaRecipe.slotDataList[i2]) && UMAPackRecipe.SlotIsValid(umaPackRecipe.slotsV3[i2]))
{
if (umaRecipe.slotDataList[i].GetOverlayList() == umaRecipe.slotDataList[i2].GetOverlayList())
{
tempPackedSlotData.copyIdx = i2;
copiedOverlays = true;
break;
}
}
}
if (copiedOverlays)
{
continue;
}
tempPackedSlotData.overlays = new PackedOverlayDataV3[umaRecipe.slotDataList[i].OverlayCount];
for (int overlayIdx = 0; overlayIdx < tempPackedSlotData.overlays.Length; overlayIdx++)
{
PackedOverlayDataV3 tempPackedOverlay = new PackedOverlayDataV3();
OverlayData overlayData = umaRecipe.slotDataList[i].GetOverlay(overlayIdx);
tempPackedOverlay.id = overlayData.overlayName;
/*
tempPackedOverlay.rect = new int[4];
tempPackedOverlay.rect[0] = Mathf.FloorToInt(overlayData.rect.x);
tempPackedOverlay.rect[1] = Mathf.FloorToInt(overlayData.rect.y);
tempPackedOverlay.rect[2] = Mathf.FloorToInt(overlayData.rect.width);
tempPackedOverlay.rect[3] = Mathf.FloorToInt(overlayData.rect.height);
*/
tempPackedOverlay.rect = new float[4];
tempPackedOverlay.rect[0] = overlayData.rect.x;
tempPackedOverlay.rect[1] = overlayData.rect.y;
tempPackedOverlay.rect[2] = overlayData.rect.width;
tempPackedOverlay.rect[3] = overlayData.rect.height;
tempPackedOverlay.isTransformed = overlayData.instanceTransformed;
tempPackedOverlay.tiling = new bool[overlayData.ChannelCount];
for (int t = 0; t < overlayData.ChannelCount; t++)
{
tempPackedOverlay.tiling[t] = overlayData.IsTextureTiled(t);
}
tempPackedOverlay.scale = overlayData.Scale;
tempPackedOverlay.rotation = overlayData.Rotation;
tempPackedOverlay.blendModes = new int[overlayData.GetOverlayBlendsLength()];
tempPackedOverlay.Tags = overlayData.tags.Clone() as string[];
tempPackedOverlay.uvOverride = overlayData.UVSet;
for (int b=0;b< overlayData.GetOverlayBlendsLength(); b++)
{
tempPackedOverlay.blendModes[b] = (int)overlayData.GetOverlayBlend(b);
}
#if (UNITY_STANDALONE || UNITY_IOS || UNITY_ANDROID || UNITY_PS4 || UNITY_XBOXONE) && !UNITY_2017_3_OR_NEWER //supported platforms for procedural materials
if (overlayData.isProcedural && (overlayData.proceduralData != null))
{
tempPackedOverlay.data = new PackedOverlaySubstanceData[overlayData.proceduralData.Length];
for (int dataIdx = 0; dataIdx < overlayData.proceduralData.Length; dataIdx++)
{
tempPackedOverlay.data[dataIdx] = new PackedOverlaySubstanceData(overlayData.proceduralData[dataIdx]);
}
}
#endif
OverlayColorData colorData = overlayData.colorData;
int colorIndex = -1;
int cIndex = 0;
for (int i1 = 0; i1 < colorEntries.Count; i1++)
{
OverlayColorData cData = colorEntries[i1];
if (cData.name != null && cData.name.Equals(colorData.name) && cData.Equals(colorData))
{
colorIndex = cIndex;
break;
}
cIndex++;
}
if (colorIndex < 0)
{
PackedOverlayColorDataV3 newColorEntry = new PackedOverlayColorDataV3(colorData);
packedColorEntries.Add(newColorEntry);
colorIndex = colorEntries.Count;
colorEntries.Add(colorData);
}
tempPackedOverlay.colorIdx = colorIndex;
tempPackedSlotData.overlays[overlayIdx] = tempPackedOverlay;
}
}
}
umaPackRecipe.fColors = packedColorEntries.ToArray();
return umaPackRecipe;
}
public static bool UnpackRecipeVersion1(UMA.UMAData.UMARecipe umaRecipe, UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
if (!UMAPackRecipe.ArrayHasData(umaPackRecipe.packedSlotDataList))
{
return false;
}
umaRecipe.slotDataList = new SlotData[umaPackRecipe.packedSlotDataList.Length];
umaRecipe.SetRace(context.GetRace(umaPackRecipe.race));
umaRecipe.ClearDna();
for (int dna = 0; dna < umaPackRecipe.packedDna.Count; dna++)
{
Type dnaType = UMADna.GetType(umaPackRecipe.packedDna[dna].dnaType);
umaRecipe.AddDna(UMADna.LoadInstance(dnaType, umaPackRecipe.packedDna[dna].packedDna));
}
for (int i = 0; i < umaPackRecipe.packedSlotDataList.Length; i++)
{
if (UMAPackRecipe.SlotIsValid(umaPackRecipe.packedSlotDataList[i]))
{
var tempSlotData = context.InstantiateSlot(umaPackRecipe.packedSlotDataList[i].slotID);
tempSlotData.overlayScale = umaPackRecipe.packedSlotDataList[i].overlayScale * 0.01f;
umaRecipe.slotDataList[i] = tempSlotData;
if (umaPackRecipe.packedSlotDataList[i].copyOverlayIndex == -1)
{
for (int overlay = 0; overlay < umaPackRecipe.packedSlotDataList[i].OverlayDataList.Length; overlay++)
{
Color tempColor;
Rect tempRect;
if (UMAPackRecipe.ArrayHasData(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].colorList))
{
tempColor = new Color(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].colorList[0] / 255.0f, umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].colorList[1] / 255.0f, umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].colorList[2] / 255.0f, umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].colorList[3] / 255.0f);
}
else
{
tempColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
}
if (UMAPackRecipe.ArrayHasData(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].rectList))
{
Rect originalRect = context.InstantiateOverlay(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].overlayID).rect;
tempRect = new Rect(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].rectList[0], umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].rectList[1], umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].rectList[2], umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].rectList[3]);
Vector2 aspectRatio = new Vector2(tempRect.width / originalRect.width, tempRect.height / originalRect.height);
tempRect = new Rect(tempRect.x / aspectRatio.x, tempRect.y / aspectRatio.y, tempRect.width / aspectRatio.x, tempRect.height / aspectRatio.y);
}
else
{
tempRect = new Rect(0, 0, 0, 0);
}
tempSlotData.AddOverlay(context.InstantiateOverlay(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].overlayID));
tempSlotData.GetOverlay(tempSlotData.OverlayCount - 1).colorData.color = tempColor;
tempSlotData.GetOverlay(tempSlotData.OverlayCount - 1).rect = tempRect;
if (UMAPackRecipe.ArrayHasData(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].channelMaskList))
{
for (int channelAdjust = 0; channelAdjust < umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].channelMaskList.Length; channelAdjust++)
{
packedOverlayData tempData = umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay];
tempSlotData.GetOverlay(tempSlotData.OverlayCount - 1).SetColor(channelAdjust, new Color32((byte)tempData.channelMaskList[channelAdjust][0],
(byte)tempData.channelMaskList[channelAdjust][1],
(byte)tempData.channelMaskList[channelAdjust][2],
(byte)tempData.channelMaskList[channelAdjust][3]));
}
}
if (UMAPackRecipe.ArrayHasData(umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].channelAdditiveMaskList))
{
for (int channelAdjust = 0; channelAdjust < umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay].channelAdditiveMaskList.Length; channelAdjust++)
{
packedOverlayData tempData = umaPackRecipe.packedSlotDataList[i].OverlayDataList[overlay];
tempSlotData.GetOverlay(tempSlotData.OverlayCount - 1).SetAdditive(channelAdjust, new Color32((byte)tempData.channelAdditiveMaskList[channelAdjust][0],
(byte)tempData.channelAdditiveMaskList[channelAdjust][1],
(byte)tempData.channelAdditiveMaskList[channelAdjust][2],
(byte)tempData.channelAdditiveMaskList[channelAdjust][3]));
}
}
}
}
else
{
tempSlotData.SetOverlayList(umaRecipe.slotDataList[umaPackRecipe.packedSlotDataList[i].copyOverlayIndex].GetOverlayList());
}
}
}
return true;
}
public static List UnPackDNA(List DNA)
{
List UnpackedDNA = new List();
for (int i = 0; i < DNA.Count; i++)
{
UMAPackedDna packedDna = DNA[i];
Type dnaType = UMADna.GetType(packedDna.dnaType);
UnpackedDNA.Add(UMADna.LoadInstance(dnaType, packedDna.packedDna));
}
return UnpackedDNA;
}
public static UMAData.UMARecipe UnpackRecipeVersion2(UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
UMAData.UMARecipe umaRecipe = new UMAData.UMARecipe();
UnpackRecipeVersion2(umaRecipe, umaPackRecipe, context);
return umaRecipe;
}
public static void UnpackRecipeVersion2(UMA.UMAData.UMARecipe umaRecipe, UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
umaRecipe.slotDataList = new SlotData[umaPackRecipe.slotsV2.Length];
if (!String.IsNullOrWhiteSpace(umaPackRecipe.race))
{
umaRecipe.SetRace(context.GetRace(umaPackRecipe.race));
}
umaRecipe.ClearDna();
List packedDna = UnPackDNA(umaPackRecipe.packedDna);
for (int i = 0; i < packedDna.Count; i++)
{
UMADnaBase umd = packedDna[i];
umaRecipe.AddDna(umd);
}
OverlayColorData[] colorData;
if (UMAPackRecipe.ArrayHasData(umaPackRecipe.fColors))
{
colorData = new OverlayColorData[umaPackRecipe.fColors.Length];
for (int i = 0; i < colorData.Length; i++)
{
colorData[i] = new OverlayColorData();
umaPackRecipe.fColors[i].SetOverlayColorData(colorData[i]);
}
}
else if (UMAPackRecipe.ArrayHasData(umaPackRecipe.colors))
{
colorData = new OverlayColorData[umaPackRecipe.colors.Length];
for (int i = 0; i < colorData.Length; i++)
{
colorData[i] = new OverlayColorData();
umaPackRecipe.colors[i].SetOverlayColorData(colorData[i]);
}
}
else
{
colorData = new OverlayColorData[0];
}
umaRecipe.sharedColors = new OverlayColorData[umaPackRecipe.sharedColorCount];
for (int i = 0; i < umaRecipe.sharedColors.Length; i++)
{
umaRecipe.sharedColors[i] = colorData[i];
}
for (int i = 0; i < umaPackRecipe.slotsV2.Length; i++)
{
PackedSlotDataV2 packedSlot = umaPackRecipe.slotsV2[i];
if (UMAPackRecipe.SlotIsValid(packedSlot))
{
var tempSlotData = context.InstantiateSlot(packedSlot.id);
tempSlotData.overlayScale = packedSlot.scale * 0.01f;
umaRecipe.slotDataList[i] = tempSlotData;
if (packedSlot.copyIdx == -1)
{
for (int i2 = 0; i2 < packedSlot.overlays.Length; i2++)
{
PackedOverlayDataV2 packedOverlay = packedSlot.overlays[i2];
OverlayData overlayData = context.InstantiateOverlay(packedOverlay.id);
overlayData.rect = new Rect(packedOverlay.rect[0],
packedOverlay.rect[1],
packedOverlay.rect[2],
packedOverlay.rect[3]);
if (packedOverlay.colorIdx < umaPackRecipe.sharedColorCount)
{
overlayData.colorData = umaRecipe.sharedColors[packedOverlay.colorIdx];
}
else
{
overlayData.colorData = colorData[packedOverlay.colorIdx].Duplicate();
overlayData.colorData.name = OverlayColorData.UNSHARED;
}
if (UMAPackRecipe.MaterialIsValid(overlayData.asset.material))
{
overlayData.EnsureChannels(overlayData.asset.material.channels.Length);
}
tempSlotData.AddOverlay(overlayData);
}
}
else
{
tempSlotData.SetOverlayList(umaRecipe.slotDataList[packedSlot.copyIdx].GetOverlayList());
}
}
}
}
public static UMAData.UMARecipe UnpackRecipeVersion3(UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
UMAData.UMARecipe umaRecipe = new UMAData.UMARecipe();
UnpackRecipeVersion3(umaRecipe, umaPackRecipe, context);
return umaRecipe;
}
public static void UnpackRecipeVersion3(UMA.UMAData.UMARecipe umaRecipe, UMAPackRecipe umaPackRecipe, UMAContextBase context)
{
umaRecipe.slotDataList = new SlotData[umaPackRecipe.slotsV3.Length];
if (!string.IsNullOrEmpty(umaPackRecipe.race))
{
var race = context.GetRace(umaPackRecipe.race);
if (race != null)
{
umaRecipe.SetRace(race);
}
}
umaRecipe.ClearDna();
List packedDna = UnPackDNA(umaPackRecipe.packedDna);
for (int i = 0; i < packedDna.Count; i++)
{
UMADnaBase umd = packedDna[i];
umaRecipe.AddDna(umd);
}
OverlayColorData[] colorData = UnpackColors(umaPackRecipe);
umaRecipe.sharedColors = new OverlayColorData[umaPackRecipe.sharedColorCount];
for (int i = 0; i < umaRecipe.sharedColors.Length; i++)
{
umaRecipe.sharedColors[i] = colorData[i];
}
for (int i = 0; i < umaPackRecipe.slotsV3.Length; i++)
{
PackedSlotDataV3 packedSlot = umaPackRecipe.slotsV3[i];
if (UMAPackRecipe.SlotIsValid(packedSlot))
{
var tempSlotData = context.InstantiateSlot(packedSlot.id);
if (tempSlotData == null)
{
if (Debug.isDebugBuild)
{
throw new UMAResourceNotFoundException("Slot " + packedSlot.id + " not found in context. Skipping.");
}
continue;
}
if (packedSlot.Tags != null)
{
tempSlotData.tags = packedSlot.Tags.Clone() as string[];
}
else
{
tempSlotData.tags = new string[0];
}
if (packedSlot.Races != null)
{
tempSlotData.Races = packedSlot.Races;
}
tempSlotData.blendShapeTargetSlot = packedSlot.blendShapeTarget;
tempSlotData.overlayScale = packedSlot.scale * 0.01f;
tempSlotData.overSmoosh = packedSlot.overSmoosh;
tempSlotData.smooshDistance = packedSlot.smooshDistance;
tempSlotData.smooshInvertDist = packedSlot.smooshInvertDist;
tempSlotData.smooshInvertX = packedSlot.smooshInvertX;
tempSlotData.smooshInvertY = packedSlot.smooshInvertY;
tempSlotData.smooshInvertZ = packedSlot.smooshInvertZ;
tempSlotData.smooshableTag = packedSlot.smooshableTag;
tempSlotData.smooshTargetTag = packedSlot.smooshTargetTag;
tempSlotData.isSwapSlot = packedSlot.isSwapSlot;
tempSlotData.swapTag = packedSlot.swapTag;
tempSlotData.UVSet = packedSlot.uvOverride;
tempSlotData.isDisabled = packedSlot.isDisabled;
tempSlotData.expandAlongNormal = packedSlot.expandAlongNormal;
umaRecipe.slotDataList[i] = tempSlotData;
if (packedSlot.copyIdx == -1)
{
for (int i2 = 0; i2 < packedSlot.overlays.Length; i2++)
{
PackedOverlayDataV3 packedOverlay = packedSlot.overlays[i2];
OverlayData overlayData = context.InstantiateOverlay(packedOverlay.id);
overlayData.rect = new Rect(
packedOverlay.rect[0],
packedOverlay.rect[1],
packedOverlay.rect[2],
packedOverlay.rect[3]);
overlayData.instanceTransformed = packedOverlay.isTransformed;
overlayData.Scale = packedOverlay.scale;
overlayData.Rotation = packedOverlay.rotation;
overlayData.UVSet = packedSlot.uvOverride;
if (packedOverlay.colorIdx < umaPackRecipe.sharedColorCount)
{
overlayData.colorData = umaRecipe.sharedColors[packedOverlay.colorIdx];
}
else
{
overlayData.colorData = colorData[packedOverlay.colorIdx].Duplicate();
overlayData.colorData.name = OverlayColorData.UNSHARED;
}
if (packedOverlay.blendModes != null)
{
overlayData.SetOverlayBlendsLength(packedOverlay.blendModes.Length);
for (int blendModeIdx = 0; blendModeIdx < packedOverlay.blendModes.Length; blendModeIdx++)
{
overlayData.SetOverlayBlend(blendModeIdx, (OverlayDataAsset.OverlayBlend)packedOverlay.blendModes[blendModeIdx]);
}
}
if (packedOverlay.Tags != null)
{
overlayData.tags = packedOverlay.Tags.Clone() as string[];
}
else
{
overlayData.tags = new string[0];
}
if (UMAPackRecipe.MaterialIsValid(overlayData.asset.material))
{
overlayData.EnsureChannels(overlayData.asset.material.channels.Length);
}
#if (UNITY_STANDALONE || UNITY_IOS || UNITY_ANDROID || UNITY_PS4 || UNITY_XBOXONE) && !UNITY_2017_3_OR_NEWER //supported platforms for procedural materials
if(packedOverlay.data == null)
overlayData.proceduralData = new OverlayData.OverlayProceduralData[0];
else
{
overlayData.proceduralData = new OverlayData.OverlayProceduralData[packedOverlay.data.Length];
for (int dataIdx = 0; dataIdx < packedOverlay.data.Length; dataIdx++)
{
OverlayData.OverlayProceduralData proceduralData = new OverlayData.OverlayProceduralData();
packedOverlay.data[dataIdx].SetOverlayProceduralData(proceduralData);
overlayData.proceduralData[dataIdx] = proceduralData;
}
}
#endif
tempSlotData.AddOverlay(overlayData);
}
}
else
{
tempSlotData.SetOverlayList(umaRecipe.slotDataList[packedSlot.copyIdx].GetOverlayList());
}
}
}
}
public static OverlayColorData[] UnpackColors(UMAPackRecipe umaPackRecipe)
{
OverlayColorData[] colorData;
if (UMAPackRecipe.ArrayHasData(umaPackRecipe.fColors))
{
colorData = new OverlayColorData[umaPackRecipe.fColors.Length];
for (int i = 0; i < colorData.Length; i++)
{
colorData[i] = new OverlayColorData();
umaPackRecipe.fColors[i].SetOverlayColorData(colorData[i]);
}
}
else if (UMAPackRecipe.ArrayHasData(umaPackRecipe.colors))
{
colorData = new OverlayColorData[umaPackRecipe.colors.Length];
for (int i = 0; i < colorData.Length; i++)
{
colorData[i] = new OverlayColorData();
umaPackRecipe.colors[i].SetOverlayColorData(colorData[i]);
}
}
else
{
colorData = new OverlayColorData[0];
}
return colorData;
}
#endregion
}
}