mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 22:03:21 +08:00
Implement proper rotation algorithm for skin editor
This commit is contained in:
parent
a55879e511
commit
27e81d6504
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -12,7 +11,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using Vector2 = osuTK.Vector2;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
{
|
{
|
||||||
@ -173,12 +172,12 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
|
|
||||||
foreach (var h in hitObjects)
|
foreach (var h in hitObjects)
|
||||||
{
|
{
|
||||||
h.Position = rotatePointAroundOrigin(h.Position, referenceOrigin.Value, delta);
|
h.Position = RotatePointAroundOrigin(h.Position, referenceOrigin.Value, delta);
|
||||||
|
|
||||||
if (h is IHasPath path)
|
if (h is IHasPath path)
|
||||||
{
|
{
|
||||||
foreach (var point in path.Path.ControlPoints)
|
foreach (var point in path.Path.ControlPoints)
|
||||||
point.Position.Value = rotatePointAroundOrigin(point.Position.Value, Vector2.Zero, delta);
|
point.Position.Value = RotatePointAroundOrigin(point.Position.Value, Vector2.Zero, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,28 +323,5 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
private OsuHitObject[] selectedMovableObjects => SelectedItems.OfType<OsuHitObject>()
|
private OsuHitObject[] selectedMovableObjects => SelectedItems.OfType<OsuHitObject>()
|
||||||
.Where(h => !(h is Spinner))
|
.Where(h => !(h is Spinner))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rotate a point around an arbitrary origin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="point">The point.</param>
|
|
||||||
/// <param name="origin">The centre origin to rotate around.</param>
|
|
||||||
/// <param name="angle">The angle to rotate (in degrees).</param>
|
|
||||||
private static Vector2 rotatePointAroundOrigin(Vector2 point, Vector2 origin, float angle)
|
|
||||||
{
|
|
||||||
angle = -angle;
|
|
||||||
|
|
||||||
point.X -= origin.X;
|
|
||||||
point.Y -= origin.Y;
|
|
||||||
|
|
||||||
Vector2 ret;
|
|
||||||
ret.X = point.X * MathF.Cos(MathUtils.DegreesToRadians(angle)) + point.Y * MathF.Sin(MathUtils.DegreesToRadians(angle));
|
|
||||||
ret.Y = point.X * -MathF.Sin(MathUtils.DegreesToRadians(angle)) + point.Y * MathF.Cos(MathUtils.DegreesToRadians(angle));
|
|
||||||
|
|
||||||
ret.X += origin.X;
|
|
||||||
ret.Y += origin.Y;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Graphics.UserInterface;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -353,6 +354,29 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
#region Helper Methods
|
#region Helper Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotate a point around an arbitrary origin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point.</param>
|
||||||
|
/// <param name="origin">The centre origin to rotate around.</param>
|
||||||
|
/// <param name="angle">The angle to rotate (in degrees).</param>
|
||||||
|
protected static Vector2 RotatePointAroundOrigin(Vector2 point, Vector2 origin, float angle)
|
||||||
|
{
|
||||||
|
angle = -angle;
|
||||||
|
|
||||||
|
point.X -= origin.X;
|
||||||
|
point.Y -= origin.Y;
|
||||||
|
|
||||||
|
Vector2 ret;
|
||||||
|
ret.X = point.X * MathF.Cos(MathUtils.DegreesToRadians(angle)) + point.Y * MathF.Sin(MathUtils.DegreesToRadians(angle));
|
||||||
|
ret.Y = point.X * -MathF.Sin(MathUtils.DegreesToRadians(angle)) + point.Y * MathF.Cos(MathUtils.DegreesToRadians(angle));
|
||||||
|
|
||||||
|
ret.X += origin.X;
|
||||||
|
ret.Y += origin.Y;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Given a flip direction, a surrounding quad for all selected objects, and a position,
|
/// Given a flip direction, a surrounding quad for all selected objects, and a position,
|
||||||
/// will return the flipped position in screen space coordinates.
|
/// will return the flipped position in screen space coordinates.
|
||||||
|
@ -18,16 +18,42 @@ namespace osu.Game.Skinning.Editor
|
|||||||
{
|
{
|
||||||
public class SkinSelectionHandler : SelectionHandler<ISkinnableDrawable>
|
public class SkinSelectionHandler : SelectionHandler<ISkinnableDrawable>
|
||||||
{
|
{
|
||||||
|
private Vector2? referenceOrigin;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinEditor skinEditor { get; set; }
|
private SkinEditor skinEditor { get; set; }
|
||||||
|
|
||||||
|
protected override void OnOperationEnded()
|
||||||
|
{
|
||||||
|
base.OnOperationEnded();
|
||||||
|
referenceOrigin = null;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool HandleRotation(float angle)
|
public override bool HandleRotation(float angle)
|
||||||
{
|
{
|
||||||
// TODO: this doesn't correctly account for origin/anchor specs being different in a multi-selection.
|
if (SelectedBlueprints.Count == 1)
|
||||||
foreach (var c in SelectedBlueprints)
|
{
|
||||||
((Drawable)c.Item).Rotation += angle;
|
// for single items, rotate around the origin rather than the selection centre.
|
||||||
|
((Drawable)SelectedBlueprints.First().Item).Rotation += angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var selectionQuad = GetSurroundingQuad(SelectedBlueprints.SelectMany(b =>
|
||||||
|
b.Item.ScreenSpaceDrawQuad.GetVertices().ToArray()));
|
||||||
|
|
||||||
return base.HandleRotation(angle);
|
referenceOrigin ??= selectionQuad.Centre;
|
||||||
|
|
||||||
|
foreach (var b in SelectedBlueprints)
|
||||||
|
{
|
||||||
|
var drawableItem = (Drawable)b.Item;
|
||||||
|
|
||||||
|
drawableItem.Position = drawableItem.Parent.ToLocalSpace(RotatePointAroundOrigin(b.ScreenSpaceSelectionPoint, referenceOrigin.Value, angle)) - drawableItem.AnchorPosition;
|
||||||
|
drawableItem.Rotation += angle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this isn't always the case but let's be lenient for now.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HandleScale(Vector2 scale, Anchor anchor)
|
public override bool HandleScale(Vector2 scale, Anchor anchor)
|
||||||
|
Loading…
Reference in New Issue
Block a user