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