// Magica Cloth 2. // Copyright (c) 2023 MagicaSoft. // https://magicasoft.jp using System; using System.Collections.Generic; using System.Threading; using Unity.Collections; using UnityEngine; namespace MagicaCloth2 { /// /// MagicaClothコンポーネント処理のデータ部分 /// public partial class ClothProcess : IDisposable, IValid, ITransform { public MagicaCloth cloth { get; internal set; } /// /// 状態フラグ(0 ~ 31) /// public const int State_Valid = 0; public const int State_Enable = 1; public const int State_ParameterDirty = 2; public const int State_InitSuccess = 3; public const int State_InitComplete = 4; public const int State_Build = 5; public const int State_Running = 6; public const int State_DisableAutoBuild = 7; public const int State_CullingInvisible = 8; // チームデータの同フラグのコピー public const int State_CullingKeep = 9; // チームデータの同フラグのコピー public const int State_SkipWriting = 10; // 書き込み停止(ストップモーション用) public const int State_SkipWritingDirty = 11; // 書き込み停止フラグ更新サイン public const int State_UsePreBuild = 12; // PreBuildを利用 /// /// 現在の状態 /// internal BitField32 stateFlag; /// /// 初期クロスコンポーネントトランスフォーム状態 /// internal TransformRecord clothTransformRecord { get; private set; } = null; /// /// レンダー情報へのハンドル /// (レンダラーのセットアップデータ) /// List renderHandleList = new List(); /// /// BoneClothのセットアップデータ /// internal RenderSetupData boneClothSetupData; /// /// レンダーメッシュの管理 /// public class RenderMeshInfo { public int renderHandle; public VirtualMeshContainer renderMeshContainer; public DataChunk mappingChunk; } internal List renderMeshInfoList = new List(); /// /// カスタムスキニングのボーン情報 /// internal List customSkinningBoneRecords = new List(); /// /// 法線調整用のトランスフォーム状態 /// internal TransformRecord normalAdjustmentTransformRecord { get; private set; } = null; //========================================================================================= /// /// ペイントマップ情報 /// public class PaintMapData { public const byte ReadFlag_Fixed = 0x01; public const byte ReadFlag_Move = 0x02; public const byte ReadFlag_Limit = 0x04; public Color32[] paintData; public int paintMapWidth; public int paintMapHeight; public ExBitFlag8 paintReadFlag; } //========================================================================================= /// /// 処理結果 /// internal ResultCode result; public ResultCode Result => result; /// /// Cloth Type /// public enum ClothType { MeshCloth = 0, BoneCloth = 1, BoneSpring = 10, } internal ClothType clothType { get; private set; } /// /// リダクション設定(外部から設定する) /// ReductionSettings reductionSettings; /// /// シミュレーションパラメータ /// public ClothParameters parameters { get; private set; } /// /// プロキシメッシュ /// public VirtualMeshContainer ProxyMeshContainer { get; private set; } = null; /// /// コライダーリスト /// コライダーが格納されるインデックスは他のデータのインデックスと一致している /// internal List colliderList = new List(); /// /// コライダー配列数 /// internal int ColliderCapacity => colliderList.Count; //========================================================================================= /// /// チームID /// public int TeamId { get; private set; } = 0; /// /// 慣性制約データ /// internal InertiaConstraint.ConstraintData inertiaConstraintData; /// /// 距離制約データ /// internal DistanceConstraint.ConstraintData distanceConstraintData; /// /// 曲げ制約データ /// internal TriangleBendingConstraint.ConstraintData bendingConstraintData; //========================================================================================= /// /// カリング用対象アニメーター /// internal Animator cullingAnimator = null; /// /// カリング用アニメーター配下のレンダラーリスト /// internal List cullingAnimatorRenderers = new List(); //========================================================================================= /// /// キャンセルトークン /// CancellationTokenSource cts = new CancellationTokenSource(); volatile object lockObject = new object(); volatile object lockState = new object(); /// /// 初期化待機カウンター /// volatile int suspendCounter = 0; /// /// 破棄フラグ /// volatile bool isDestory = false; /// /// 内部データまで完全に破棄されたかどうか /// volatile bool isDestoryInternal = false; /// /// 構築中フラグ /// volatile bool isBuild = false; public BitField32 GetStateFlag() { lock (lockState) { // copy var state = stateFlag; return state; } } public bool IsState(int state) { lock (lockState) { return stateFlag.IsSet(state); } } public void SetState(int state, bool sw) { lock (lockState) { stateFlag.SetBits(state, sw); } } public bool IsValid() => IsState(State_Valid); public bool IsCullingInvisible() => IsState(State_CullingInvisible); public bool IsCullingKeep() => IsState(State_CullingKeep); public bool IsSkipWriting() => IsState(State_SkipWriting); public bool IsEnable { get { if (IsValid() == false || TeamId == 0) return false; return MagicaManager.Team.IsEnable(TeamId); } } public bool HasProxyMesh { get { if (IsValid() == false || TeamId == 0) return false; return ProxyMeshContainer?.shareVirtualMesh?.IsSuccess ?? false; } } public string Name => cloth != null ? cloth.name : "(none)"; //========================================================================================= public ClothProcess() { // 初期状態 result = ResultCode.Empty; } public void Dispose() { lock (lockObject) { isDestory = true; SetState(State_Valid, false); result.Clear(); cts.Cancel(); } DisposeInternal(); //Debug.Log($"ClothProcessData.Dispose()!"); } void DisposeInternal() { lock (lockObject) { // すでに破棄完了ならば不要 if (isDestoryInternal) return; // ビルド中は破棄を保留する if (isBuild) return; // マネージャから削除 MagicaManager.Simulation?.ExitProxyMesh(this); MagicaManager.VMesh?.ExitProxyMesh(TeamId); // マッピングメッシュも解放される MagicaManager.Collider?.Exit(this); MagicaManager.Cloth?.RemoveCloth(this); // レンダーメッシュの破棄 foreach (var info in renderMeshInfoList) { if (info == null) continue; // 仮想メッシュ破棄 info.renderMeshContainer?.Dispose(); } renderMeshInfoList.Clear(); renderMeshInfoList = null; // レンダーデータの利用終了 foreach (int renderHandle in renderHandleList) { MagicaManager.Render?.RemoveRenderer(renderHandle); } renderHandleList.Clear(); renderHandleList = null; // BoneClothセットアップデータ boneClothSetupData?.Dispose(); boneClothSetupData = null; // プロキシメッシュ破棄 ProxyMeshContainer?.Dispose(); ProxyMeshContainer = null; colliderList.Clear(); cullingAnimator = null; cullingAnimatorRenderers.Clear(); // PreBuildデータ解除 MagicaManager.PreBuild?.UnregisterPreBuildData(cloth?.GetSerializeData2()?.preBuildData.GetSharePreBuildData()); // 完全破棄フラグ isDestoryInternal = true; } Develop.DebugLog($"Cloth dispose internal."); // 破棄監視リストから削除する MagicaManager.Team.RemoveMonitoringProcess(this); } internal void IncrementSuspendCounter() { lock (lockObject) { suspendCounter++; } } internal void DecrementSuspendCounter() { lock (lockObject) { suspendCounter--; } } internal int GetSuspendCounter() { return suspendCounter; } public RenderMeshInfo GetRenderMeshInfo(int index) { if (index >= 0 && index < renderMeshInfoList.Count) return renderMeshInfoList[index]; else return null; } internal void SyncParameters() { parameters = cloth.SerializeData.GetClothParameters(); } public void GetUsedTransform(HashSet transformSet) { cloth.SerializeData.GetUsedTransform(transformSet); cloth.serializeData2.GetUsedTransform(transformSet); clothTransformRecord?.GetUsedTransform(transformSet); boneClothSetupData?.GetUsedTransform(transformSet); renderHandleList.ForEach(handle => MagicaManager.Render.GetRendererData(handle).GetUsedTransform(transformSet)); customSkinningBoneRecords.ForEach(rd => rd.GetUsedTransform(transformSet)); normalAdjustmentTransformRecord?.GetUsedTransform(transformSet); } public void ReplaceTransform(Dictionary replaceDict) { cloth.SerializeData.ReplaceTransform(replaceDict); cloth.serializeData2.ReplaceTransform(replaceDict); clothTransformRecord?.ReplaceTransform(replaceDict); boneClothSetupData?.ReplaceTransform(replaceDict); renderHandleList.ForEach(handle => MagicaManager.Render.GetRendererData(handle).ReplaceTransform(replaceDict)); customSkinningBoneRecords.ForEach(rd => rd.ReplaceTransform(replaceDict)); normalAdjustmentTransformRecord?.ReplaceTransform(replaceDict); } internal void SetSkipWriting(bool sw) { // ここではフラグのみ更新する // 実際の更新はチームのAlwaysTeamUpdate()で行われる SetState(State_SkipWriting, sw); SetState(State_SkipWritingDirty, true); } } }