2019-01-24 16:43:03 +08:00
// 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.
2018-04-13 17:19:50 +08:00
2019-11-01 18:22:07 +08:00
using System.Collections.Generic ;
using System.Linq ;
using osu.Framework.Extensions ;
2018-04-13 17:19:50 +08:00
using osu.Framework.Graphics ;
2019-11-01 14:34:24 +08:00
using osu.Framework.Graphics.Containers ;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{
2019-11-01 14:34:24 +08:00
public class FollowPointRenderer : CompositeDrawable
2018-04-13 17:19:50 +08:00
{
2019-11-01 18:22:07 +08:00
private readonly List < FollowPointGroup > groups = new List < FollowPointGroup > ( ) ;
2018-04-13 17:19:50 +08:00
/// <summary>
2019-11-01 14:39:23 +08:00
/// Adds the <see cref="FollowPoint"/>s around a <see cref="DrawableOsuHitObject"/>.
/// This includes <see cref="FollowPoint"/>s leading into <paramref name="hitObject"/>, and <see cref="FollowPoint"/>s exiting <paramref name="hitObject"/>.
2018-04-13 17:19:50 +08:00
/// </summary>
2019-11-01 14:39:23 +08:00
/// <param name="hitObject">The <see cref="DrawableOsuHitObject"/> to add <see cref="FollowPoint"/>s for.</param>
public void AddFollowPoints ( DrawableOsuHitObject hitObject )
2019-11-01 18:22:07 +08:00
= > addGroup ( new FollowPointGroup ( hitObject ) . With ( g = > g . StartTime . BindValueChanged ( _ = > onStartTimeChanged ( g ) ) ) ) ;
/// <summary>
/// Removes the <see cref="FollowPoint"/>s around a <see cref="DrawableOsuHitObject"/>.
/// This includes <see cref="FollowPoint"/>s leading into <paramref name="hitObject"/>, and <see cref="FollowPoint"/>s exiting <paramref name="hitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="DrawableOsuHitObject"/> to remove <see cref="FollowPoint"/>s for.</param>
public void RemoveFollowPoints ( DrawableOsuHitObject hitObject ) = > removeGroup ( groups . Single ( g = > g . Start = = hitObject ) ) ;
/// <summary>
/// Adds a <see cref="FollowPointGroup"/> to this <see cref="FollowPointRenderer"/>.
/// </summary>
/// <param name="group">The <see cref="FollowPointGroup"/> to add.</param>
/// <returns>The index of <paramref name="group"/> in <see cref="groups"/>.</returns>
private int addGroup ( FollowPointGroup group )
2018-04-13 17:19:50 +08:00
{
2019-11-01 18:22:07 +08:00
AddInternal ( group ) ;
2019-11-01 14:39:23 +08:00
2019-11-01 18:22:07 +08:00
// Groups are sorted by their start time when added such that the index can be used to post-process other surrounding groups
int index = groups . AddInPlace ( group , Comparer < FollowPointGroup > . Create ( ( g1 , g2 ) = > g1 . StartTime . Value . CompareTo ( g2 . StartTime . Value ) ) ) ;
2019-11-01 14:39:23 +08:00
2019-11-01 18:22:07 +08:00
if ( index < groups . Count - 1 )
2018-04-13 17:19:50 +08:00
{
2019-11-01 18:22:07 +08:00
// Update the group's end point to the next hitobject
2019-11-01 14:39:23 +08:00
// h1 -> -> -> h2
// hitObject nextGroup
2019-02-27 20:07:17 +08:00
2019-11-01 18:22:07 +08:00
FollowPointGroup nextGroup = groups [ index + 1 ] ;
group . End = nextGroup . Start ;
2018-04-13 17:19:50 +08:00
}
2019-11-05 18:31:48 +08:00
else
group . End = null ;
2019-02-27 20:07:17 +08:00
2019-11-01 18:22:07 +08:00
if ( index > 0 )
2018-04-13 17:19:50 +08:00
{
2019-11-01 18:22:07 +08:00
// Previous group's end point to the current group's start point
2019-11-01 14:39:23 +08:00
// h1 -> -> -> h2
// prevGroup hitObject
2019-02-27 20:07:17 +08:00
2019-11-01 18:22:07 +08:00
FollowPointGroup previousGroup = groups [ index - 1 ] ;
previousGroup . End = group . Start ;
2018-04-13 17:19:50 +08:00
}
2019-11-01 18:22:07 +08:00
return index ;
2018-04-13 17:19:50 +08:00
}
2019-11-01 14:39:23 +08:00
/// <summary>
2019-11-01 18:22:07 +08:00
/// Removes a <see cref="FollowPointGroup"/> from this <see cref="FollowPointRenderer"/>.
2019-11-01 14:39:23 +08:00
/// </summary>
2019-11-01 18:22:07 +08:00
/// <param name="group">The <see cref="FollowPointGroup"/> to remove.</param>
/// <returns>Whether <paramref name="group"/> was removed.</returns>
private bool removeGroup ( FollowPointGroup group )
2018-04-13 17:19:50 +08:00
{
2019-11-01 18:22:07 +08:00
RemoveInternal ( group ) ;
2018-04-13 17:19:50 +08:00
2019-11-01 18:22:07 +08:00
int index = groups . IndexOf ( group ) ;
2019-04-01 11:16:05 +08:00
2019-11-01 18:22:07 +08:00
if ( index > 0 )
2018-04-13 17:19:50 +08:00
{
2019-11-01 18:22:07 +08:00
// Update the previous group's end point to the next group's start point
// h1 -> -> -> h2 -> -> -> h3
// prevGroup group nextGroup
// The current group's end point is used since there may not be a next group
FollowPointGroup previousGroup = groups [ index - 1 ] ;
previousGroup . End = group . End ;
2018-04-13 17:19:50 +08:00
}
2019-11-01 14:39:23 +08:00
2019-11-01 18:22:07 +08:00
return groups . Remove ( group ) ;
2019-11-01 14:39:23 +08:00
}
2019-11-01 18:22:07 +08:00
private void onStartTimeChanged ( FollowPointGroup group )
2019-11-01 14:39:23 +08:00
{
2019-11-01 18:22:07 +08:00
// Naive but can be improved if performance becomes problematic
removeGroup ( group ) ;
addGroup ( group ) ;
2018-04-13 17:19:50 +08:00
}
}
}