using System; using System.Collections.Generic; using UnityEngine; using UMA.PoseTools; #if UNITY_EDITOR using UnityEditor; #endif namespace UMA { [System.Serializable] public class BonePoseDNAConverterPlugin : DynamicDNAPlugin { [SerializeField] private List _poseDNAConverters = new List(); public List poseDNAConverters { get { return _poseDNAConverters; } set { _poseDNAConverters = value; } } #region BACKWARDS COMPATIBILITY //the following are backwards compatible methods for DynamicDNAConverterBehaviour.StartingPose //TODO can we make this work again? //backwards compatibility public UMABonePose StartingPose { get { /*if(_poseDNAConverters.Count > 0) { for(int i = 0; i < _poseDNAConverters.Count; i++) { if (_poseDNAConverters[i].poseToApply != null && (_poseDNAConverters[i].startingPoseWeight.defaultWeight == 1 > 0f) return _poseDNAConverters[i].poseToApply; } }*/ return null; } //this is not bulletproof but it will be obsolete anyway set { /*if(_poseDNAConverters.Count > 0) { int foundIndex = -1; for(int i = 0; i < _poseDNAConverters.Count; i++) { if (_poseDNAConverters[i].poseToApply == value) { foundIndex = i; break; } } if(foundIndex >= 0 && foundIndex != 0) { //move the existing entry to 0 var current = new BonePoseDNAConverter(_poseDNAConverters[foundIndex]); _poseDNAConverters.RemoveAt(foundIndex); _poseDNAConverters.Insert(0, current); return; } } _poseDNAConverters.Insert(0, new BonePoseDNAConverter(value, 1f));*/ } } //backwards compatibility public float StartingPoseWeight { get { /*if (_poseDNAConverters.Count > 0) { for (int i = 0; i < _poseDNAConverters.Count; i++) { if (_poseDNAConverters[i].poseToApply != null && _poseDNAConverters[i].defaultPoseWeight > 0f) return _poseDNAConverters[i].defaultPoseWeight; } }*/ return 0f; } set { /*if (_poseDNAConverters.Count > 0) { _poseDNAConverters[0].defaultPoseWeight = value; }*/ } } #endregion #region DYNAMICDNAPLUGIN PROPERTIES #if UNITY_EDITOR public override string PluginHelp { get { return "Bone Pose DNA Converters convert the set dna names into weight settings for UMA Bone Pose that will be applied to a character. You can use the 'Starting Pose Weight' to force this pose on all characters that use this converter at the start. Or you can hook up to a modifying dna so that the pose is only applied based on a characters dna value."; } } #endif #endregion #region REQUIRED DYNAMICDNAPLUGIN METHODS /// /// Returns a dictionary of all the dna names in use by the plugin and the entries in its converter list that reference them /// /// public override Dictionary> IndexesForDnaNames { get { var dict = new Dictionary>(); for (int i = 0; i < _poseDNAConverters.Count; i++) { for (int ci = 0; ci < _poseDNAConverters[i].UsedDNANames.Count; ci++) { if (!dict.ContainsKey(_poseDNAConverters[i].UsedDNANames[ci])) { dict.Add(_poseDNAConverters[i].UsedDNANames[ci], new List()); } dict[_poseDNAConverters[i].UsedDNANames[ci]].Add(i); } } return dict; } } /// /// Apply the boneposes according to the given dna (determined by the dnaTypeHash) /// /// /// /// public override void ApplyDNA(UMAData umaData, UMASkeleton skeleton, int dnaTypeHash) { var umaDna = umaData.GetDna(dnaTypeHash); var masterWeightCalc = masterWeight.GetWeight(umaDna); for (int i = 0; i < _poseDNAConverters.Count; i++) { _poseDNAConverters[i].ApplyDNA(umaData, skeleton, dnaTypeHash, masterWeightCalc); } } #endregion #region INSPECTOR GUI OVERRIDES #if UNITY_EDITOR public override string[] ImportSettingsMethods { get { return new string[] { "Add", "Replace" }; } } public override GUIContent GetPluginEntryLabel(SerializedProperty entry, SerializedObject pluginSO, int entryIndex) { if (_poseDNAConverters[entryIndex].poseToApply != null) { return new GUIContent(_poseDNAConverters[entryIndex].poseToApply.name); } return base.GetPluginEntryLabel(entry, pluginSO, entryIndex); } public override bool ImportSettings(UnityEngine.Object pluginToImport, int importMethod) { //TODO Deal with Morphset? var importPlug = pluginToImport as BonePoseDNAConverterPlugin; if (importPlug == null) { Debug.LogWarning("The plugin you are trying to import was not a PoseDNAConverterPlugin!"); return false; } if (importPlug._poseDNAConverters.Count == 0) { Debug.LogWarning("The plugin you are trying to import had no settings!"); return false; } //Method Replace if (importMethod == 1) { _poseDNAConverters.Clear(); } for (int i = 0; i < importPlug._poseDNAConverters.Count; i++) { _poseDNAConverters.Add(new BonePoseDNAConverter(importPlug._poseDNAConverters[i])); } EditorUtility.SetDirty(this); AssetDatabase.SaveAssets(); return true; } #endif #endregion #region SPECIAL TYPES [System.Serializable] public class BonePoseDNAConverter { #region FIELDS [Tooltip("The UMABonePose to apply to the character. This will effectively 'morph' the character into a different shape (using bone deformation so clothes will still fit).")] [SerializeField] private UMABonePose _poseToApply; [SerializeField] [Tooltip("Make the default weight 1 to apply the pose on start to *all* characters that use this converter or set to 0 so the pose is only applied by 'Modifying DNA' below. If you want to affect this 'per character' use 'Modifying DNA' instead")] [Range(0f, 1f)] private float _startingPoseWeight = 0f; [SerializeField] [Tooltip("Add dna(s) here that will change the amount that this Pose is applied depending on their evaluated value.")] private DNAEvaluatorList _modifyingDNA = new DNAEvaluatorList(); #endregion #region PRIVATE VARS private float _livePoseWeight = 0f; //private int _dnaIndex = -1; private DynamicUMADnaBase _activeDNA; #endregion #region PUBLIC PROPERTIES public UMABonePose poseToApply { get { return _poseToApply; } set { _poseToApply = value; } } public float startingPoseWeight { get { return _startingPoseWeight; } set { _startingPoseWeight = value; } } public DNAEvaluatorList modifyingDNA { get { return _modifyingDNA; } set { _modifyingDNA = new DNAEvaluatorList(value); } } //TODO Timeline properties for screwing with the modifying dnas? public List UsedDNANames { get { //Do we include masterDNA in this? //It will make a dna entry where every entry in any plugin that uses the name shows up //could be more annoying/confusing than useful return _modifyingDNA.UsedDNANames; } } #endregion #region CONSTRUCTOR public BonePoseDNAConverter() { } public BonePoseDNAConverter(UMABonePose poseToApply, float startingPoseWeight, DNAEvaluatorList modifyingDnas) { this._poseToApply = poseToApply; this._startingPoseWeight = startingPoseWeight; if (modifyingDnas != null) { this._modifyingDNA = new DNAEvaluatorList(modifyingDnas); } } public BonePoseDNAConverter(UMABonePose poseToApply, float startingPoseWeight = 0f, List modifyingDnas = null) { this._poseToApply = poseToApply; this._startingPoseWeight = startingPoseWeight; if(modifyingDnas != null) { this._modifyingDNA = new DNAEvaluatorList(modifyingDnas); } } public BonePoseDNAConverter(BonePoseDNAConverter other) { this._poseToApply = other._poseToApply; this.startingPoseWeight = other._startingPoseWeight; this._modifyingDNA = new DNAEvaluatorList(other._modifyingDNA); } #endregion #region METHODS public void ApplyDNA(UMAData umaData, UMASkeleton skeleton, UMADnaBase activeDNA, float masterWeight = 1f) { if (_poseToApply == null) { if (Debug.isDebugBuild) { Debug.LogWarning(umaData.gameObject.name + " had an invalid or empty pose set in its BonePoseDNAConverters in its DNAConverterController"); } return; } _livePoseWeight = _startingPoseWeight; //dna weight superceeds startingWeight if it exists if (_modifyingDNA.UsedDNANames.Count > 0) { _livePoseWeight = _modifyingDNA.Evaluate(activeDNA); } _livePoseWeight = _livePoseWeight * masterWeight; _livePoseWeight = Mathf.Clamp(_livePoseWeight, 0f, 1f); _poseToApply.ApplyPose(skeleton, _livePoseWeight); } public void ApplyDNA(UMAData umaData, UMASkeleton skeleton, int dnaTypeHash, float masterWeight = 1f) { if (_poseToApply == null) { if (Debug.isDebugBuild) { Debug.LogWarning(umaData.gameObject.name + " had an invalid or empty pose set in its BonePoseDNAConverters in its DNAConverterController"); } return; } _livePoseWeight = _startingPoseWeight; //dna weight superceeds startingWeight if it exists if (_modifyingDNA.UsedDNANames.Count > 0) { _activeDNA = (DynamicUMADnaBase)umaData.GetDna(dnaTypeHash); _livePoseWeight = _modifyingDNA.Evaluate(_activeDNA); } _livePoseWeight = _livePoseWeight * masterWeight; _livePoseWeight = Mathf.Clamp(_livePoseWeight, 0f, 1f); _poseToApply.ApplyPose(skeleton, _livePoseWeight); } #endregion } #endregion } }