CustomGizmo.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using System;
  2. using System.Reflection;
  3. using UnityEngine;
  4. namespace MeidoPhotoStudio.Plugin;
  5. public class CustomGizmo : GizmoRender
  6. {
  7. public GizmoMode Mode;
  8. private static readonly Camera Camera = GameMain.Instance.MainCamera.camera;
  9. #pragma warning disable SA1310, SA1311
  10. // TODO: Refactor reflection to using private members directly.
  11. private static new readonly FieldInfo is_drag_ = Utility.GetFieldInfo<GizmoRender>("is_drag_");
  12. #pragma warning restore SA1310, SA1311
  13. private new readonly FieldInfo beSelectedType = Utility.GetFieldInfo<GizmoRender>("beSelectedType");
  14. private GizmoType gizmoType;
  15. private Transform target;
  16. private bool hasAlternateTarget;
  17. private Transform positionTransform;
  18. private Vector3 positionOld = Vector3.zero;
  19. private Vector3 deltaPosition = Vector3.zero;
  20. private Vector3 deltaLocalPosition = Vector3.zero;
  21. private Quaternion rotationOld = Quaternion.identity;
  22. private Quaternion deltaRotation = Quaternion.identity;
  23. private Quaternion deltaLocalRotation = Quaternion.identity;
  24. private Vector3 deltaScale = Vector3.zero;
  25. private Vector3 scaleOld = Vector3.one;
  26. private GizmoType gizmoTypeOld;
  27. public event EventHandler GizmoDrag;
  28. public enum GizmoType
  29. {
  30. Rotate,
  31. Move,
  32. Scale,
  33. }
  34. public enum GizmoMode
  35. {
  36. Local,
  37. World,
  38. Global,
  39. }
  40. public static bool IsDrag
  41. {
  42. get => (bool)is_drag_.GetValue(null);
  43. private set => is_drag_.SetValue(null, value);
  44. }
  45. public GizmoType CurrentGizmoType
  46. {
  47. get => gizmoType;
  48. set
  49. {
  50. gizmoType = value;
  51. if (gizmoTypeOld == gizmoType)
  52. return;
  53. gizmoTypeOld = gizmoType;
  54. eAxis = gizmoType is GizmoType.Move;
  55. eScal = gizmoType is GizmoType.Scale;
  56. eRotate = gizmoType is GizmoType.Rotate;
  57. }
  58. }
  59. public bool IsGizmoDrag =>
  60. GizmoVisible && IsDrag && SelectedType is not 0;
  61. public bool GizmoVisible
  62. {
  63. get => Visible;
  64. set
  65. {
  66. if (value && IsDrag)
  67. IsDrag = false;
  68. Visible = value;
  69. }
  70. }
  71. private int SelectedType =>
  72. (int)beSelectedType.GetValue(this);
  73. public static CustomGizmo Make(Transform target, float scale = 0.25f, GizmoMode mode = GizmoMode.Local)
  74. {
  75. var gizmoGo = new GameObject($"[MPS Gizmo {target.gameObject.name}]");
  76. gizmoGo.transform.SetParent(target);
  77. var gizmo = gizmoGo.AddComponent<CustomGizmo>();
  78. gizmo.target = target;
  79. gizmo.lineRSelectedThick = 0.25f;
  80. gizmo.offsetScale = scale;
  81. gizmo.Mode = mode;
  82. gizmo.CurrentGizmoType = GizmoType.Rotate;
  83. return gizmo;
  84. }
  85. public override void Update()
  86. {
  87. BeginUpdate();
  88. base.Update();
  89. if (IsGizmoDrag)
  90. SetTargetTransform();
  91. SetTransform();
  92. EndUpdate();
  93. }
  94. public void SetAlternateTarget(Transform trans)
  95. {
  96. positionTransform = trans;
  97. hasAlternateTarget = trans != null;
  98. }
  99. private void BeginUpdate()
  100. {
  101. var rotation = transform.rotation;
  102. deltaPosition = transform.position - positionOld;
  103. deltaRotation = rotation * Quaternion.Inverse(rotationOld);
  104. deltaLocalPosition = transform.InverseTransformVector(deltaPosition);
  105. deltaLocalRotation = Quaternion.Inverse(rotationOld) * rotation;
  106. deltaScale = transform.localScale - scaleOld;
  107. }
  108. private void EndUpdate()
  109. {
  110. var transform = this.transform;
  111. positionOld = transform.position;
  112. rotationOld = transform.rotation;
  113. scaleOld = transform.localScale;
  114. }
  115. private void SetTargetTransform()
  116. {
  117. bool dragged;
  118. switch (Mode)
  119. {
  120. case GizmoMode.Local:
  121. target.position += target.transform.TransformVector(deltaLocalPosition).normalized
  122. * deltaLocalPosition.magnitude;
  123. target.rotation *= deltaLocalRotation;
  124. target.localScale += deltaScale;
  125. dragged = deltaLocalRotation != Quaternion.identity || deltaLocalPosition != Vector3.zero
  126. || deltaScale != Vector3.zero;
  127. break;
  128. case GizmoMode.World:
  129. case GizmoMode.Global:
  130. target.position += deltaPosition;
  131. target.rotation = deltaRotation * target.rotation;
  132. dragged = deltaRotation != Quaternion.identity || deltaPosition != Vector3.zero;
  133. break;
  134. default:
  135. throw new ArgumentOutOfRangeException();
  136. }
  137. if (dragged)
  138. OnGizmoDrag();
  139. }
  140. private void SetTransform()
  141. {
  142. var transform = this.transform;
  143. transform.position = (hasAlternateTarget ? positionTransform : target).position;
  144. transform.localScale = Vector3.one;
  145. transform.rotation = Mode switch
  146. {
  147. GizmoMode.Local => target.rotation,
  148. GizmoMode.World => Quaternion.identity,
  149. GizmoMode.Global => Quaternion.LookRotation(transform.position - Camera.transform.position),
  150. _ => target.rotation,
  151. };
  152. }
  153. private void OnGizmoDrag() =>
  154. GizmoDrag?.Invoke(this, EventArgs.Empty);
  155. }