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