mirror of
https://github.com/ppy/osu
synced 2025-03-03 01:49:46 +00:00
Merge branch 'master' into skin-component-settings
This commit is contained in:
commit
e79bed8fbe
@ -2,23 +2,22 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Skinning;
|
||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@ -126,18 +125,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
|
||||
Samples.Samples = HitObject.TailSamples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||
|
||||
var slidingSamples = new List<ISampleInfo>();
|
||||
|
||||
var normalSample = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL);
|
||||
if (normalSample != null)
|
||||
slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(normalSample).With("sliderslide"));
|
||||
|
||||
var whistleSample = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||
if (whistleSample != null)
|
||||
slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(whistleSample).With("sliderwhistle"));
|
||||
|
||||
slidingSample.Samples = slidingSamples.ToArray();
|
||||
slidingSample.Samples = HitObject.CreateSlidingSamples().Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||
}
|
||||
|
||||
public override void StopAllSamples()
|
||||
|
@ -74,6 +74,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
||||
}
|
||||
|
||||
protected override void LoadSamples()
|
||||
{
|
||||
// Tail models don't actually get samples, as the playback is handled by DrawableSlider.
|
||||
// This override is only here for visibility in explaining this weird flow.
|
||||
}
|
||||
|
||||
public override void PlaySamples()
|
||||
{
|
||||
// Tail models don't actually get samples, as the playback is handled by DrawableSlider.
|
||||
// This override is only here for visibility in explaining this weird flow.
|
||||
}
|
||||
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
base.UpdateInitialTransforms();
|
||||
|
@ -121,15 +121,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
base.LoadSamples();
|
||||
|
||||
var firstSample = HitObject.Samples.FirstOrDefault();
|
||||
|
||||
if (firstSample != null)
|
||||
{
|
||||
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample).With("spinnerspin");
|
||||
|
||||
spinningSample.Samples = new ISampleInfo[] { clone };
|
||||
spinningSample.Frequency.Value = spinning_sample_initial_frequency;
|
||||
}
|
||||
spinningSample.Samples = HitObject.CreateSpinningSamples().Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||
spinningSample.Frequency.Value = spinning_sample_initial_frequency;
|
||||
}
|
||||
|
||||
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
||||
|
@ -29,6 +29,23 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
||||
}
|
||||
|
||||
public override IList<HitSampleInfo> AuxiliarySamples => CreateSlidingSamples().Concat(TailSamples).ToArray();
|
||||
|
||||
public IList<HitSampleInfo> CreateSlidingSamples()
|
||||
{
|
||||
var slidingSamples = new List<HitSampleInfo>();
|
||||
|
||||
var normalSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL);
|
||||
if (normalSample != null)
|
||||
slidingSamples.Add(normalSample.With("sliderslide"));
|
||||
|
||||
var whistleSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||
if (whistleSample != null)
|
||||
slidingSamples.Add(whistleSample.With("sliderwhistle"));
|
||||
|
||||
return slidingSamples;
|
||||
}
|
||||
|
||||
private readonly Cached<Vector2> endPositionCache = new Cached<Vector2>();
|
||||
|
||||
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
||||
|
@ -1,7 +1,11 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
@ -73,5 +77,20 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||
|
||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||
|
||||
public override IList<HitSampleInfo> AuxiliarySamples => CreateSpinningSamples();
|
||||
|
||||
public HitSampleInfo[] CreateSpinningSamples()
|
||||
{
|
||||
var referenceSample = Samples.FirstOrDefault();
|
||||
|
||||
if (referenceSample == null)
|
||||
return Array.Empty<HitSampleInfo>();
|
||||
|
||||
return new[]
|
||||
{
|
||||
SampleControlPoint.ApplyTo(referenceSample).With("spinnerspin")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
||||
public void ApplyToDrawableRuleset(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
||||
{
|
||||
drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset;
|
||||
drawableTaikoRuleset.LockPlayfieldAspect.Value = false;
|
||||
}
|
||||
|
||||
public void Update(Playfield playfield)
|
||||
|
@ -29,6 +29,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
public new BindableDouble TimeRange => base.TimeRange;
|
||||
|
||||
public readonly BindableBool LockPlayfieldAspect = new BindableBool(true);
|
||||
|
||||
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
|
||||
|
||||
protected override bool UserScrollSpeedAdjustment => false;
|
||||
@ -70,7 +72,10 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
return ControlPoints[result];
|
||||
}
|
||||
|
||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer
|
||||
{
|
||||
LockPlayfieldAspect = { BindTarget = LockPlayfieldAspect }
|
||||
};
|
||||
|
||||
protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo);
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
/// <summary>
|
||||
/// Default height of a <see cref="TaikoPlayfield"/> when inside a <see cref="DrawableTaikoRuleset"/>.
|
||||
/// </summary>
|
||||
public const float DEFAULT_HEIGHT = 212;
|
||||
public const float DEFAULT_HEIGHT = 200;
|
||||
|
||||
private Container<HitExplosion> hitExplosionContainer;
|
||||
private Container<KiaiHitExplosion> kiaiExplosionContainer;
|
||||
|
@ -2,9 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
@ -13,16 +13,22 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768;
|
||||
private const float default_aspect = 16f / 9f;
|
||||
|
||||
public readonly IBindable<bool> LockPlayfieldAspect = new BindableBool(true);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
float aspectAdjust = Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect;
|
||||
Size = new Vector2(1, default_relative_height * aspectAdjust);
|
||||
float height = default_relative_height;
|
||||
|
||||
if (LockPlayfieldAspect.Value)
|
||||
height *= Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect;
|
||||
|
||||
Height = height;
|
||||
|
||||
// Position the taiko playfield exactly one playfield from the top of the screen.
|
||||
RelativePositionAxes = Axes.Y;
|
||||
Y = Size.Y;
|
||||
Y = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Skinning;
|
||||
@ -22,6 +25,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Cached]
|
||||
private Storyboard storyboard { get; set; } = new Storyboard();
|
||||
|
||||
private IEnumerable<DrawableStoryboardSprite> sprites => this.ChildrenOfType<DrawableStoryboardSprite>();
|
||||
|
||||
[Test]
|
||||
public void TestSkinSpriteDisallowedByDefault()
|
||||
{
|
||||
@ -41,9 +46,54 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||
|
||||
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.Centre, Vector2.Zero)));
|
||||
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||
|
||||
assertSpritesFromSkin(true);
|
||||
|
||||
AddAssert("skinnable sprite has correct size", () => sprites.Any(s => Precision.AlmostEquals(s.ChildrenOfType<SkinnableSprite>().Single().Size, new Vector2(128, 128))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFlippedSprite()
|
||||
{
|
||||
const string lookup_name = "hitcircleoverlay";
|
||||
|
||||
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||
AddStep("flip sprites", () => sprites.ForEach(s =>
|
||||
{
|
||||
s.FlipH = true;
|
||||
s.FlipV = true;
|
||||
}));
|
||||
AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeScale()
|
||||
{
|
||||
const string lookup_name = "hitcircleoverlay";
|
||||
|
||||
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||
AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(-1)));
|
||||
AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNegativeScaleWithFlippedSprite()
|
||||
{
|
||||
const string lookup_name = "hitcircleoverlay";
|
||||
|
||||
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||
AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(-1)));
|
||||
AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight));
|
||||
AddStep("flip sprites", () => sprites.ForEach(s =>
|
||||
{
|
||||
s.FlipH = true;
|
||||
s.FlipV = true;
|
||||
}));
|
||||
AddAssert("origin back", () => sprites.All(s => s.Origin == Anchor.TopLeft));
|
||||
}
|
||||
|
||||
private DrawableStoryboardSprite createSprite(string lookupName, Anchor origin, Vector2 initialPosition)
|
||||
@ -57,7 +107,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private void assertSpritesFromSkin(bool fromSkin) =>
|
||||
AddAssert($"sprites are {(fromSkin ? "from skin" : "from storyboard")}",
|
||||
() => this.ChildrenOfType<DrawableStoryboardSprite>()
|
||||
.All(sprite => sprite.ChildrenOfType<SkinnableSprite>().Any() == fromSkin));
|
||||
() => sprites.All(sprite => sprite.ChildrenOfType<SkinnableSprite>().Any() == fromSkin));
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ namespace osu.Game
|
||||
/// </summary>
|
||||
private const double global_track_volume_adjust = 0.8;
|
||||
|
||||
public bool UseDevelopmentServer { get; }
|
||||
public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
|
||||
|
||||
public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version();
|
||||
|
||||
@ -177,7 +177,6 @@ namespace osu.Game
|
||||
|
||||
public OsuGameBase()
|
||||
{
|
||||
UseDevelopmentServer = DebugUtils.IsDebugBuild;
|
||||
Name = @"osu!";
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
@ -67,6 +68,12 @@ namespace osu.Game.Rulesets.Objects
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any samples which may be used by this hit object that are non-standard.
|
||||
/// This is used only to preload these samples ahead of time.
|
||||
/// </summary>
|
||||
public virtual IList<HitSampleInfo> AuxiliarySamples => ImmutableList<HitSampleInfo>.Empty;
|
||||
|
||||
public SampleControlPoint SampleControlPoint = SampleControlPoint.DEFAULT;
|
||||
public DifficultyControlPoint DifficultyControlPoint = DifficultyControlPoint.DEFAULT;
|
||||
|
||||
|
@ -500,12 +500,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
=> new LegacyHitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newVolume.GetOr(Volume), newCustomSampleBank.GetOr(CustomSampleBank), newIsLayered.GetOr(IsLayered));
|
||||
|
||||
public bool Equals(LegacyHitSampleInfo? other)
|
||||
=> base.Equals(other) && CustomSampleBank == other.CustomSampleBank && IsLayered == other.IsLayered;
|
||||
=> base.Equals(other) && CustomSampleBank == other.CustomSampleBank;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is LegacyHitSampleInfo other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), CustomSampleBank, IsLayered);
|
||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), CustomSampleBank);
|
||||
}
|
||||
|
||||
private class FileHitSampleInfo : LegacyHitSampleInfo, IEquatable<FileHitSampleInfo>
|
||||
|
@ -3,22 +3,22 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -264,10 +264,25 @@ namespace osu.Game.Rulesets.UI
|
||||
var entry = CreateLifetimeEntry(hitObject);
|
||||
lifetimeEntryMap[entry.HitObject] = entry;
|
||||
|
||||
preloadSamples(hitObject);
|
||||
|
||||
HitObjectContainer.Add(entry);
|
||||
OnHitObjectAdded(entry.HitObject);
|
||||
}
|
||||
|
||||
private void preloadSamples(HitObject hitObject)
|
||||
{
|
||||
// prepare sample pools ahead of time so we're not initialising at runtime.
|
||||
foreach (var sample in hitObject.Samples)
|
||||
prepareSamplePool(hitObject.SampleControlPoint.ApplyTo(sample));
|
||||
|
||||
foreach (var sample in hitObject.AuxiliarySamples)
|
||||
prepareSamplePool(hitObject.SampleControlPoint.ApplyTo(sample));
|
||||
|
||||
foreach (var nestedObject in hitObject.NestedHitObjects)
|
||||
preloadSamples(nestedObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a <see cref="HitObjectLifetimeEntry"/> for a pooled <see cref="HitObject"/> from this <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
@ -330,22 +345,7 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
DrawableHitObject IPooledHitObjectProvider.GetPooledDrawableRepresentation(HitObject hitObject, DrawableHitObject parent)
|
||||
{
|
||||
var lookupType = hitObject.GetType();
|
||||
|
||||
IDrawablePool pool;
|
||||
|
||||
// Tests may add derived hitobject instances for which pools don't exist. Try to find any applicable pool and dynamically assign the type if the pool exists.
|
||||
if (!pools.TryGetValue(lookupType, out pool))
|
||||
{
|
||||
foreach (var (t, p) in pools)
|
||||
{
|
||||
if (!t.IsInstanceOfType(hitObject))
|
||||
continue;
|
||||
|
||||
pools[lookupType] = pool = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var pool = prepareDrawableHitObjectPool(hitObject);
|
||||
|
||||
return (DrawableHitObject)pool?.Get(d =>
|
||||
{
|
||||
@ -372,14 +372,39 @@ namespace osu.Game.Rulesets.UI
|
||||
});
|
||||
}
|
||||
|
||||
private IDrawablePool prepareDrawableHitObjectPool(HitObject hitObject)
|
||||
{
|
||||
var lookupType = hitObject.GetType();
|
||||
|
||||
IDrawablePool pool;
|
||||
|
||||
// Tests may add derived hitobject instances for which pools don't exist. Try to find any applicable pool and dynamically assign the type if the pool exists.
|
||||
if (!pools.TryGetValue(lookupType, out pool))
|
||||
{
|
||||
foreach (var (t, p) in pools)
|
||||
{
|
||||
if (!t.IsInstanceOfType(hitObject))
|
||||
continue;
|
||||
|
||||
pools[lookupType] = pool = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
private readonly Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>> samplePools = new Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>>();
|
||||
|
||||
public PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo)
|
||||
{
|
||||
if (!samplePools.TryGetValue(sampleInfo, out var existingPool))
|
||||
AddInternal(samplePools[sampleInfo] = existingPool = new DrawableSamplePool(sampleInfo, 1));
|
||||
public PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo) => prepareSamplePool(sampleInfo).Get();
|
||||
|
||||
return existingPool.Get();
|
||||
private DrawablePool<PoolableSkinnableSample> prepareSamplePool(ISampleInfo sampleInfo)
|
||||
{
|
||||
if (samplePools.TryGetValue(sampleInfo, out var pool)) return pool;
|
||||
|
||||
AddInternal(samplePools[sampleInfo] = pool = new DrawableSamplePool(sampleInfo, 1));
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
private class DrawableSamplePool : DrawablePool<PoolableSkinnableSample>
|
||||
|
@ -134,6 +134,9 @@ namespace osu.Game.Skinning.Editor
|
||||
{
|
||||
Debug.Assert(skinEditor != null);
|
||||
|
||||
if (!target.IsCurrentScreen())
|
||||
return;
|
||||
|
||||
if (!target.IsLoaded)
|
||||
{
|
||||
Scheduler.AddOnce(setTarget, target);
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
@ -73,31 +72,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
protected override Vector2 DrawScale
|
||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y) * VectorScale;
|
||||
|
||||
public override Anchor Origin
|
||||
{
|
||||
get
|
||||
{
|
||||
var origin = base.Origin;
|
||||
|
||||
if (FlipH)
|
||||
{
|
||||
if (origin.HasFlagFast(Anchor.x0))
|
||||
origin = Anchor.x2 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||
else if (origin.HasFlagFast(Anchor.x2))
|
||||
origin = Anchor.x0 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||
}
|
||||
|
||||
if (FlipV)
|
||||
{
|
||||
if (origin.HasFlagFast(Anchor.y0))
|
||||
origin = Anchor.y2 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||
else if (origin.HasFlagFast(Anchor.y2))
|
||||
origin = Anchor.y0 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
public override Anchor Origin => StoryboardExtensions.AdjustOrigin(base.Origin, VectorScale, FlipH, FlipV);
|
||||
|
||||
public override bool IsPresent
|
||||
=> !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
@ -73,31 +72,7 @@ namespace osu.Game.Storyboards.Drawables
|
||||
protected override Vector2 DrawScale
|
||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y) * VectorScale;
|
||||
|
||||
public override Anchor Origin
|
||||
{
|
||||
get
|
||||
{
|
||||
var origin = base.Origin;
|
||||
|
||||
if (FlipH)
|
||||
{
|
||||
if (origin.HasFlagFast(Anchor.x0))
|
||||
origin = Anchor.x2 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||
else if (origin.HasFlagFast(Anchor.x2))
|
||||
origin = Anchor.x0 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||
}
|
||||
|
||||
if (FlipV)
|
||||
{
|
||||
if (origin.HasFlagFast(Anchor.y0))
|
||||
origin = Anchor.y2 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||
else if (origin.HasFlagFast(Anchor.y2))
|
||||
origin = Anchor.y0 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
public override Anchor Origin => StoryboardExtensions.AdjustOrigin(base.Origin, VectorScale, FlipH, FlipV);
|
||||
|
||||
public override bool IsPresent
|
||||
=> !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent;
|
||||
|
@ -104,7 +104,13 @@ namespace osu.Game.Storyboards
|
||||
drawable = new Sprite { Texture = textureStore.Get(storyboardPath) };
|
||||
// if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy.
|
||||
else if (UseSkinSprites)
|
||||
drawable = new SkinnableSprite(path);
|
||||
{
|
||||
drawable = new SkinnableSprite(path)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
|
||||
return drawable;
|
||||
}
|
||||
|
43
osu.Game/Storyboards/StoryboardExtensions.cs
Normal file
43
osu.Game/Storyboards/StoryboardExtensions.cs
Normal file
@ -0,0 +1,43 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Storyboards
|
||||
{
|
||||
public static class StoryboardExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Given an origin and a set of properties, adjust the origin to display the sprite/animation correctly.
|
||||
/// </summary>
|
||||
/// <param name="origin">The current origin.</param>
|
||||
/// <param name="vectorScale">The vector scale.</param>
|
||||
/// <param name="flipH">Whether the element is flipped horizontally.</param>
|
||||
/// <param name="flipV">Whether the element is flipped vertically.</param>
|
||||
/// <returns>The adjusted origin.</returns>
|
||||
public static Anchor AdjustOrigin(Anchor origin, Vector2 vectorScale, bool flipH, bool flipV)
|
||||
{
|
||||
// Either flip horizontally or negative X scale, but not both.
|
||||
if (flipH ^ (vectorScale.X < 0))
|
||||
{
|
||||
if (origin.HasFlagFast(Anchor.x0))
|
||||
origin = Anchor.x2 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||
else if (origin.HasFlagFast(Anchor.x2))
|
||||
origin = Anchor.x0 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||
}
|
||||
|
||||
// Either flip vertically or negative Y scale, but not both.
|
||||
if (flipV ^ (vectorScale.Y < 0))
|
||||
{
|
||||
if (origin.HasFlagFast(Anchor.y0))
|
||||
origin = Anchor.y2 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||
else if (origin.HasFlagFast(Anchor.y2))
|
||||
origin = Anchor.y0 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user