A game about forced loneliness, made by TACStudios
at master 593 lines 22 kB view raw
1using UnityEngine; 2 3namespace UnityEditor.U2D.Animation 4{ 5 internal class SkeletonView : ISkeletonView 6 { 7 internal const string deleteCommandName = "Delete"; 8 internal const string softDeleteCommandName = "SoftDelete"; 9 10 const float k_PickingRadius = 5f; 11 static readonly int k_BodyHashCode = "Body".GetHashCode(); 12 static readonly int k_JointHashCode = "Joint".GetHashCode(); 13 static readonly int k_TailHashCode = "Tail".GetHashCode(); 14 static readonly int k_CreateBoneHashCode = "CreateBone".GetHashCode(); 15 16 public int InvalidID { get; set; } 17 public SkeletonMode mode { get; set; } 18 public int defaultControlID { get; set; } 19 public int hoveredBoneID => m_HoveredBoneID; 20 public int hoveredJointID => m_HoveredJointID; 21 public int hoveredBodyID => m_HoveredBodyID; 22 public int hoveredTailID => m_HoveredTailID; 23 public int hotBoneID => m_HotBoneID; 24 25 IGUIWrapper m_GUIWrapper; 26 int m_RotateControlID = -1; 27 int m_MoveControlID = -1; 28 int m_FreeMoveControlID = -1; 29 int m_MoveJointControlID = -1; 30 int m_MoveEndPositionControlID = -1; 31 int m_ChangeLengthControlID = -1; 32 int m_CreateBoneControlID = -1; 33 int m_HoveredBoneID = 0; 34 int m_PrevHoveredBoneID = 0; 35 int m_HoveredBodyID = 0; 36 int m_HoveredJointID = 0; 37 int m_HoveredTailID = 0; 38 int m_HotBoneID = 0; 39 int m_HoveredBodyControlID = -1; 40 int m_HoveredJointControlID = -1; 41 int m_HoveredTailControlID = -1; 42 float m_NearestDistance; 43 float m_NearestBodyDistance; 44 float m_NearestJointDistance; 45 float m_NearestTailDistance; 46 int m_NearestBodyId = 0; 47 int m_NearestJointId = 0; 48 int m_NearestTailId = 0; 49 SliderData m_HoveredSliderData = SliderData.zero; 50 SliderData m_HotSliderData = SliderData.zero; 51 52 public SkeletonView(IGUIWrapper gw) 53 { 54 m_GUIWrapper = gw; 55 } 56 57 public void BeginLayout() 58 { 59 m_HoveredBodyControlID = m_GUIWrapper.GetControlID(k_BodyHashCode, FocusType.Passive); 60 m_HoveredJointControlID = m_GUIWrapper.GetControlID(k_JointHashCode, FocusType.Passive); 61 m_HoveredTailControlID = m_GUIWrapper.GetControlID(k_TailHashCode, FocusType.Passive); 62 m_CreateBoneControlID = m_GUIWrapper.GetControlID(k_CreateBoneHashCode, FocusType.Passive); 63 64 if (m_GUIWrapper.eventType == EventType.Layout) 65 { 66 m_PrevHoveredBoneID = m_HoveredBoneID; 67 m_NearestDistance = float.MaxValue; 68 m_NearestBodyDistance = float.MaxValue; 69 m_NearestJointDistance = float.MaxValue; 70 m_NearestTailDistance = float.MaxValue; 71 m_NearestBodyId = InvalidID; 72 m_NearestJointId = InvalidID; 73 m_NearestTailId = InvalidID; 74 m_HoveredBoneID = InvalidID; 75 m_HoveredBodyID = InvalidID; 76 m_HoveredJointID = InvalidID; 77 m_HoveredTailID = InvalidID; 78 m_HoveredSliderData = SliderData.zero; 79 80 if (m_GUIWrapper.IsControlHot(0)) 81 { 82 m_RotateControlID = -1; 83 m_MoveControlID = -1; 84 m_FreeMoveControlID = -1; 85 m_MoveJointControlID = -1; 86 m_MoveEndPositionControlID = -1; 87 m_ChangeLengthControlID = -1; 88 m_HotBoneID = InvalidID; 89 } 90 } 91 } 92 93 public void EndLayout() 94 { 95 m_GUIWrapper.LayoutControl(m_HoveredBodyControlID, m_NearestBodyDistance * 0.25f); 96 m_GUIWrapper.LayoutControl(m_HoveredJointControlID, m_NearestJointDistance); 97 m_GUIWrapper.LayoutControl(m_HoveredTailControlID, m_NearestTailDistance); 98 99 if (m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID)) 100 { 101 m_HoveredBoneID = m_NearestBodyId; 102 m_HoveredBodyID = m_NearestBodyId; 103 } 104 105 if (m_GUIWrapper.IsControlNearest(m_HoveredJointControlID)) 106 { 107 m_HoveredBoneID = m_NearestJointId; 108 m_HoveredJointID = m_NearestJointId; 109 } 110 111 if (m_GUIWrapper.IsControlNearest(m_HoveredTailControlID)) 112 { 113 m_HoveredBoneID = m_NearestTailId; 114 m_HoveredTailID = m_NearestTailId; 115 } 116 117 if ((m_GUIWrapper.eventType == EventType.Layout && m_PrevHoveredBoneID != m_HoveredBoneID) || m_GUIWrapper.eventType == EventType.MouseMove) 118 m_GUIWrapper.Repaint(); 119 } 120 121 public bool CanLayout() 122 { 123 return m_GUIWrapper.eventType == EventType.Layout; 124 } 125 126 public void LayoutBone(int id, Vector3 position, Vector3 endPosition, Vector3 forward, Vector3 up, Vector3 right, bool isChainEnd) 127 { 128 if (mode == SkeletonMode.Disabled) 129 return; 130 131 var sliderData = new SliderData() 132 { 133 position = GetMouseWorldPosition(forward, position), 134 forward = forward, 135 up = up, 136 right = right 137 }; 138 139 { 140 var distance = m_GUIWrapper.DistanceToSegmentClamp(position, endPosition); 141 142 if (distance <= m_NearestDistance) 143 { 144 m_NearestDistance = distance; 145 m_NearestBodyDistance = distance; 146 m_NearestBodyId = id; 147 m_HoveredSliderData = sliderData; 148 } 149 } 150 151 { 152 var distance = m_GUIWrapper.DistanceToCircle(position, GetBoneRadiusForPicking(position) * 2f); 153 154 if (distance <= m_NearestDistance) 155 { 156 m_NearestDistance = distance; 157 m_NearestJointDistance = distance; 158 m_NearestJointId = id; 159 m_HoveredSliderData = sliderData; 160 } 161 } 162 163 if (isChainEnd && 164 (IsCapable(SkeletonAction.ChangeLength) || 165 IsCapable(SkeletonAction.MoveEndPosition) || 166 IsCapable(SkeletonAction.CreateBone))) 167 { 168 var distance = m_GUIWrapper.DistanceToCircle(endPosition, GetBoneRadiusForPicking(endPosition)); 169 170 if (distance <= m_NearestDistance) 171 { 172 m_NearestDistance = distance; 173 m_NearestTailDistance = distance; 174 m_NearestTailId = id; 175 m_HoveredSliderData = sliderData; 176 } 177 } 178 } 179 180 public Vector3 GetMouseWorldPosition(Vector3 planeNormal, Vector3 planePosition) 181 { 182 return m_GUIWrapper.GUIToWorld(m_GUIWrapper.mousePosition, planeNormal, planePosition); 183 } 184 185 float GetBoneRadiusForPicking(Vector3 position) 186 { 187 if (m_GUIWrapper.HasCurrentCamera()) 188 return 0.1f * m_GUIWrapper.GetHandleSize(position); 189 190 return k_PickingRadius; 191 } 192 193 public bool DoSelectBone(out int id, out bool additive) 194 { 195 id = 0; 196 additive = false; 197 198 if (IsActionTriggering(SkeletonAction.Select)) 199 { 200 id = m_HoveredBoneID; 201 additive = m_GUIWrapper.isActionKeyDown; 202 203 if (mode == SkeletonMode.Selection) 204 { 205 m_GUIWrapper.UseCurrentEvent(); 206 m_GUIWrapper.SetGuiChanged(true); 207 } 208 209 return true; 210 } 211 212 return false; 213 } 214 215 public bool DoRotateBone(Vector3 pivot, Vector3 normal, out float deltaAngle) 216 { 217 deltaAngle = 0f; 218 219 var oldPosition = m_HotSliderData.position; 220 if (DoSliderAction(SkeletonAction.RotateBone, m_HoveredBodyControlID, ref m_RotateControlID, out var newPosition)) 221 { 222 deltaAngle = Vector3.SignedAngle(oldPosition - pivot, (Vector3)newPosition - pivot, normal); 223 return true; 224 } 225 226 return false; 227 } 228 229 public bool DoMoveBone(out Vector3 deltaPosition) 230 { 231 deltaPosition = Vector3.zero; 232 233 var oldPosition = m_HotSliderData.position; 234 if (DoSliderAction(SkeletonAction.MoveBone, m_HoveredJointControlID, ref m_MoveControlID, out var newPosition)) 235 { 236 deltaPosition = newPosition - oldPosition; 237 return true; 238 } 239 240 return false; 241 } 242 243 public bool DoFreeMoveBone(out Vector3 deltaPosition) 244 { 245 deltaPosition = Vector3.zero; 246 247 var oldPosition = m_HotSliderData.position; 248 if (DoSliderAction(SkeletonAction.FreeMoveBone, m_HoveredBodyControlID, ref m_FreeMoveControlID, out var newPosition)) 249 { 250 deltaPosition = newPosition - oldPosition; 251 return true; 252 } 253 254 return false; 255 } 256 257 public bool DoMoveJoint(out Vector3 deltaPosition) 258 { 259 deltaPosition = Vector3.zero; 260 261 var oldPosition = m_HotSliderData.position; 262 if (DoSliderAction(SkeletonAction.MoveJoint, m_HoveredJointControlID, ref m_MoveJointControlID, out var newPosition)) 263 { 264 deltaPosition = newPosition - oldPosition; 265 return true; 266 } 267 268 return false; 269 } 270 271 public bool DoMoveEndPosition(out Vector3 endPosition) 272 { 273 return DoSliderAction(SkeletonAction.MoveEndPosition, m_HoveredTailControlID, ref m_MoveEndPositionControlID, out endPosition); 274 } 275 276 public bool DoChangeLength(out Vector3 endPosition) 277 { 278 return DoSliderAction(SkeletonAction.ChangeLength, m_HoveredTailControlID, ref m_ChangeLengthControlID, out endPosition); 279 } 280 281 bool DoSliderAction(SkeletonAction action, int controlID, ref int actionControlID, out Vector3 newPosition) 282 { 283 newPosition = m_HoveredSliderData.position; 284 285 if (IsActionTriggering(action)) 286 { 287 actionControlID = controlID; 288 m_HotSliderData = m_HoveredSliderData; 289 m_HotBoneID = hoveredBoneID; 290 } 291 292 if (m_GUIWrapper.DoSlider(actionControlID, m_HotSliderData, out newPosition)) 293 { 294 m_HotSliderData.position = newPosition; 295 return true; 296 } 297 298 return false; 299 } 300 301 public bool DoCreateBoneStart(out Vector3 position) 302 { 303 position = GetMouseWorldPosition(m_HoveredSliderData.forward, m_HoveredSliderData.position); 304 305 if (CanCreateBone()) 306 m_GUIWrapper.LayoutControl(m_CreateBoneControlID, 0f); 307 308 if (IsActionActive(SkeletonAction.CreateBone)) 309 ConsumeMouseMoveEvents(); 310 311 if (IsActionTriggering(SkeletonAction.CreateBone)) 312 { 313 m_HotBoneID = hoveredBoneID; 314 m_GUIWrapper.SetMultiStepControlHot(m_CreateBoneControlID); 315 m_GUIWrapper.UseCurrentEvent(); 316 return true; 317 } 318 319 return false; 320 } 321 322 public bool CanCreateBone() 323 { 324 return mode == SkeletonMode.CreateBone && (m_GUIWrapper.IsControlNearest(defaultControlID) || m_GUIWrapper.IsControlNearest(m_HoveredTailControlID)); 325 } 326 327 public bool DoCreateBone(out Vector3 position) 328 { 329 position = GetMouseWorldPosition(m_HoveredSliderData.forward, m_HoveredSliderData.position); 330 331 if (IsActionHot(SkeletonAction.CreateBone)) 332 ConsumeMouseMoveEvents(); 333 334 if (IsActionFinishing(SkeletonAction.CreateBone)) 335 { 336 m_GUIWrapper.UseCurrentEvent(); 337 m_GUIWrapper.SetGuiChanged(true); 338 return true; 339 } 340 341 return false; 342 } 343 344 public bool DoSplitBone(out int id, out Vector3 position) 345 { 346 id = m_HoveredBodyID; 347 position = GetMouseWorldPosition(m_HoveredSliderData.forward, m_HoveredSliderData.position); 348 349 if (IsActionActive(SkeletonAction.SplitBone)) 350 ConsumeMouseMoveEvents(); 351 352 if (IsActionTriggering(SkeletonAction.SplitBone)) 353 { 354 m_GUIWrapper.UseCurrentEvent(); 355 m_GUIWrapper.SetGuiChanged(true); 356 return true; 357 } 358 359 return false; 360 } 361 362 public bool DoRemoveBone() 363 { 364 if (IsActionTriggering(SkeletonAction.Remove)) 365 { 366 m_GUIWrapper.UseCurrentEvent(); 367 m_GUIWrapper.SetGuiChanged(true); 368 return true; 369 } 370 371 return false; 372 } 373 374 public bool DoCancelMultistepAction(bool force) 375 { 376 if (force) 377 { 378 m_GUIWrapper.SetMultiStepControlHot(0); 379 return true; 380 } 381 382 if ((!m_GUIWrapper.IsMultiStepControlHot(0) && (m_GUIWrapper.IsMouseDown(1) || m_GUIWrapper.IsKeyDown(KeyCode.Escape)))) 383 { 384 m_GUIWrapper.SetMultiStepControlHot(0); 385 m_GUIWrapper.UseCurrentEvent(); 386 return true; 387 } 388 389 return false; 390 } 391 392 public bool IsActionActive(SkeletonAction action) 393 { 394 if (m_GUIWrapper.isAltDown || !m_GUIWrapper.IsControlHot(0) || !m_GUIWrapper.IsMultiStepControlHot(0)) 395 return false; 396 397 if (action == SkeletonAction.None) 398 return m_GUIWrapper.IsControlNearest(defaultControlID); 399 400 if (!IsCapable(action)) 401 return false; 402 403 if (action == SkeletonAction.RotateBone) 404 return m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID); 405 406 if (action == SkeletonAction.ChangeLength) 407 return m_GUIWrapper.IsControlNearest(m_HoveredTailControlID) && !m_GUIWrapper.isShiftDown; 408 409 if (action == SkeletonAction.MoveJoint) 410 return m_GUIWrapper.IsControlNearest(m_HoveredJointControlID); 411 412 if (action == SkeletonAction.MoveEndPosition) 413 return m_GUIWrapper.IsControlNearest(m_HoveredTailControlID) && !m_GUIWrapper.isShiftDown; 414 415 if (action == SkeletonAction.FreeMoveBone) 416 return m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID); 417 418 if (action == SkeletonAction.MoveBone) 419 return m_GUIWrapper.IsControlNearest(m_HoveredJointControlID); 420 421 bool canCreateBone = IsCapable(SkeletonAction.CreateBone) && m_GUIWrapper.IsControlNearest(m_CreateBoneControlID); 422 bool canSplitBone = IsCapable(SkeletonAction.SplitBone) && m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID); 423 424 if (action == SkeletonAction.CreateBone) 425 return canCreateBone; 426 427 if (action == SkeletonAction.SplitBone) 428 return canSplitBone; 429 430 if (action == SkeletonAction.Select) 431 return (m_GUIWrapper.IsControlNearest(m_HoveredBodyControlID) && !canSplitBone) || 432 m_GUIWrapper.IsControlNearest(m_HoveredJointControlID) || 433 (m_GUIWrapper.IsControlNearest(m_HoveredTailControlID) && !canCreateBone); 434 435 if (action == SkeletonAction.Remove) 436 return true; 437 438 return false; 439 } 440 441 public bool IsActionHot(SkeletonAction action) 442 { 443 if (action == SkeletonAction.None) 444 return m_GUIWrapper.IsControlHot(0) && m_GUIWrapper.IsMultiStepControlHot(0); 445 446 if (action == SkeletonAction.RotateBone) 447 return m_GUIWrapper.IsControlHot(m_RotateControlID); 448 449 if (action == SkeletonAction.MoveBone) 450 return m_GUIWrapper.IsControlHot(m_MoveControlID); 451 452 if (action == SkeletonAction.FreeMoveBone) 453 return m_GUIWrapper.IsControlHot(m_FreeMoveControlID); 454 455 if (action == SkeletonAction.MoveJoint) 456 return m_GUIWrapper.IsControlHot(m_MoveJointControlID); 457 458 if (action == SkeletonAction.MoveEndPosition) 459 return m_GUIWrapper.IsControlHot(m_MoveEndPositionControlID); 460 461 if (action == SkeletonAction.ChangeLength) 462 return m_GUIWrapper.IsControlHot(m_ChangeLengthControlID); 463 464 if (action == SkeletonAction.CreateBone) 465 return m_GUIWrapper.IsMultiStepControlHot(m_CreateBoneControlID) && !m_GUIWrapper.isAltDown; 466 467 return false; 468 } 469 470 public bool IsActionTriggering(SkeletonAction action) 471 { 472 if (!IsActionActive(action)) 473 return false; 474 475 if (action == SkeletonAction.Remove) 476 { 477 if ((m_GUIWrapper.eventType == EventType.ValidateCommand || m_GUIWrapper.eventType == EventType.ExecuteCommand) 478 && (m_GUIWrapper.commandName == softDeleteCommandName || m_GUIWrapper.commandName == deleteCommandName)) 479 { 480 if (m_GUIWrapper.eventType == EventType.ExecuteCommand) 481 return true; 482 483 m_GUIWrapper.UseCurrentEvent(); 484 } 485 486 return false; 487 } 488 489 return m_GUIWrapper.IsMouseDown(0); 490 } 491 492 public bool IsActionFinishing(SkeletonAction action) 493 { 494 if (!IsActionHot(action) || !IsCapable(action)) 495 return false; 496 497 if (m_GUIWrapper.IsEventOutsideWindow()) 498 return true; 499 500 if (action == SkeletonAction.CreateBone) 501 return m_GUIWrapper.IsMouseDown(0); 502 503 return m_GUIWrapper.IsMouseUp(0); 504 } 505 506 public bool IsRepainting() 507 { 508 return m_GUIWrapper.IsRepainting(); 509 } 510 511 public void DrawBone(Vector3 position, Vector3 right, Vector3 forward, float length, Color color, bool isChained, bool isSelected, bool isJointHovered, bool isTailHovered, bool isHot) 512 { 513 var endPosition = position + right * length; 514 var rotation = Quaternion.LookRotation(forward, Vector3.Cross(right, forward)); 515 var boneJointColor = new Color(0f, 0f, 0f, 0.75f * color.a); 516 var tailColor = new Color(0f, 0f, 0f, 0.75f * color.a); 517 var hoveredColor = Handles.preselectionColor; 518 var selectedColor = Handles.selectedColor; 519 var drawRectCap = false; 520 521 if (isJointHovered) 522 boneJointColor = hoveredColor; 523 if (isHot && (IsActionHot(SkeletonAction.MoveBone) || IsActionHot(SkeletonAction.MoveJoint))) 524 boneJointColor = selectedColor; 525 526 if (mode == SkeletonMode.EditPose || mode == SkeletonMode.CreateBone) 527 { 528 if (isJointHovered || isSelected) 529 drawRectCap = true; 530 } 531 else if (mode == SkeletonMode.EditJoints || mode == SkeletonMode.SplitBone) 532 { 533 rotation = Quaternion.identity; 534 drawRectCap = true; 535 } 536 537 if (drawRectCap) 538 Handles.RectangleHandleCap(0, position, rotation, BoneDrawingUtility.GetBoneRadius(position), EventType.Repaint); 539 540 BoneDrawingUtility.DrawBone(position, endPosition, forward, color); 541 BoneDrawingUtility.DrawBoneNode(position, forward, boneJointColor); 542 543 if (!isChained && 544 (IsCapable(SkeletonAction.ChangeLength) || 545 IsCapable(SkeletonAction.MoveEndPosition))) 546 { 547 if (isTailHovered) 548 tailColor = hoveredColor; 549 550 if (isHot && (IsActionHot(SkeletonAction.ChangeLength) || IsActionHot(SkeletonAction.MoveEndPosition))) 551 tailColor = selectedColor; 552 553 BoneDrawingUtility.DrawBoneNode(endPosition, forward, tailColor); 554 } 555 } 556 557 public void DrawBoneParentLink(Vector3 parentPosition, Vector3 position, Vector3 forward, Color color) 558 { 559 BoneDrawingUtility.DrawBone(position, parentPosition, forward, color); 560 } 561 562 public void DrawBoneOutline(Vector3 position, Vector3 right, Vector3 forward, float length, Color color, float outlineScale) 563 { 564 BoneDrawingUtility.DrawBoneOutline(position, position + right * length, forward, color, outlineScale); 565 } 566 567 public void DrawCursors(bool canBeActive) 568 { 569 var mouseScreenRect = new Rect(m_GUIWrapper.mousePosition.x - 100f, m_GUIWrapper.mousePosition.y - 100f, 200f, 200f); 570 571 var isRotateHot = IsActionHot(SkeletonAction.RotateBone); 572 if ((canBeActive && IsActionActive(SkeletonAction.RotateBone)) || isRotateHot) 573 EditorGUIUtility.AddCursorRect(mouseScreenRect, MouseCursor.RotateArrow); 574 575 if ((canBeActive && IsActionActive(SkeletonAction.MoveBone)) || IsActionHot(SkeletonAction.MoveBone) || 576 (canBeActive && IsActionActive(SkeletonAction.FreeMoveBone)) || IsActionHot(SkeletonAction.FreeMoveBone) || 577 (canBeActive && IsActionActive(SkeletonAction.MoveJoint)) || IsActionHot(SkeletonAction.MoveJoint) || 578 (canBeActive && IsActionActive(SkeletonAction.MoveEndPosition)) || IsActionHot(SkeletonAction.MoveEndPosition)) 579 EditorGUIUtility.AddCursorRect(mouseScreenRect, MouseCursor.MoveArrow); 580 } 581 582 void ConsumeMouseMoveEvents() 583 { 584 if (m_GUIWrapper.eventType == EventType.MouseMove || (m_GUIWrapper.eventType == EventType.MouseDrag && m_GUIWrapper.mouseButton == 0)) 585 m_GUIWrapper.UseCurrentEvent(); 586 } 587 588 bool IsCapable(SkeletonAction action) 589 { 590 return ((int)mode & (int)action) != 0; 591 } 592 } 593}