// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System;
using System.Runtime.CompilerServices;
namespace MagicaCloth2
{
///
/// 頂点の属性
///
[System.Serializable]
public struct VertexAttribute : IEquatable
{
///
/// ビットフラグ
///
public const byte Flag_Fixed = 0x01; // 固定
public const byte Flag_Move = 0x02; // 移動
//public const byte Flag_Ignore = 0x04; // 無視(シミュレーションの対象としない):一旦オミット!
public const byte Flag_InvalidMotion = 0x08; // モーション制約無効
public const byte Flag_DisableCollision = 0x10; // コリジョン無効
public const byte Flag_Triangle = 0x80; // この頂点はトライアングルに属している
public static readonly VertexAttribute Invalid = new VertexAttribute();
public static readonly VertexAttribute Fixed = new VertexAttribute(Flag_Fixed);
public static readonly VertexAttribute Move = new VertexAttribute(Flag_Move);
public static readonly VertexAttribute DisableCollision = new VertexAttribute(Flag_DisableCollision);
//=========================================================================================
///
/// 属性値(ビットフラグ)
///
public byte Value;
//=========================================================================================
public VertexAttribute(byte initialValue = 0)
{
Value = initialValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
Value = 0;
}
///
/// フラグ設定
///
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetFlag(byte flag, bool sw)
{
if (sw)
Value |= flag;
else
Value = (byte)(Value & ~flag);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetFlag(VertexAttribute attr, bool sw)
{
if (sw)
Value |= attr.Value;
else
Value = (byte)(Value & ~attr.Value);
}
///
/// フラグ判定
///
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsSet(byte flag)
{
return (Value & flag) != 0;
}
///
/// 無効属性判定(Move/Fixed/Ignoreのどれでもない場合)
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsInvalid() => IsSet(Flag_Fixed | Flag_Move) == false;
//public bool IsInvalid() => IsSet(Flag_Fixed | Flag_Move | Flag_Ignore) == false;
///
/// 固定属性判定
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsFixed() => IsSet(Flag_Fixed);
///
/// 移動属性判定
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMove() => IsSet(Flag_Move);
///
/// 移動しないパーティクルか判定する
/// これは固定属性以外にも掴まれたことにより動かなくなったパーティクルも含まれる
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsDontMove() => !IsSet(Flag_Move);
///
/// 無視属性判定
///
///
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public bool IsIgnore() => IsSet(Flag_Ignore);
///
/// モーション制約の有効判定
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMotion() => IsSet(Flag_InvalidMotion) == false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsDisableCollision() => IsSet(Flag_DisableCollision);
//=========================================================================================
///
/// 2つの頂点属性を結合して新しい属性を返す
/// 基本的に属性値が低い方が優先される(無効(0)>固定(1)>移動(2))
///
///
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static VertexAttribute JoinAttribute(VertexAttribute attr1, VertexAttribute attr2)
{
// todo:ここは頂点属性が増えると厄介かも
return attr1.Value < attr2.Value ? attr1 : attr2;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(VertexAttribute other)
{
return Value == other.Value;
}
public override bool Equals(object obj)
{
return obj is VertexAttribute converted && Equals(converted);
}
public override int GetHashCode()
{
return Value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(VertexAttribute lhs, VertexAttribute rhs) { return lhs.Value == rhs.Value; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(VertexAttribute lhs, VertexAttribute rhs) { return lhs.Value != rhs.Value; }
}
}