diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png new file mode 100644 index 0000000000..982cc1d259 Binary files /dev/null and b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/LongNoteTailWang.png differ diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini index 9c987efc60..7c51036d69 100644 --- a/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini +++ b/osu.Game.Rulesets.Mania.Tests/Resources/special-skin/skin.ini @@ -14,4 +14,6 @@ Hit200: mania/hit200@2x Hit300: mania/hit300@2x Hit300g: mania/hit300g@2x StageLeft: mania/stage-left -StageRight: mania/stage-right \ No newline at end of file +StageRight: mania/stage-right +NoteImage0L: LongNoteTailWang +NoteImage1L: LongNoteTailWang diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index c928ebb3e0..6887674a1f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -54,6 +54,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy float lightScale = GetColumnSkinConfig(skin, LegacyManiaSkinConfigurationLookups.HoldNoteLightScale)?.Value ?? 1; + float minimumColumnWidth = GetColumnSkinConfig(skin, LegacyManiaSkinConfigurationLookups.MinimumColumnWidth)?.Value + ?? 1; + // Create a temporary animation to retrieve the number of frames, in an effort to calculate the intended frame length. // This animation is discarded and re-queried with the appropriate frame length afterwards. var tmp = skin.GetAnimation(lightImage, true, false); @@ -92,7 +95,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy d.RelativeSizeAxes = Axes.Both; d.Size = Vector2.One; d.FillMode = FillMode.Stretch; - // Todo: Wrap + d.Height = minimumColumnWidth / d.DrawWidth * 1.6f; + // Todo: Wrap? }); if (bodySprite != null) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 19e8bc7092..2761a93290 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -7,9 +7,12 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Text; +using System.Threading; +using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -18,6 +21,8 @@ using osu.Game.Audio; using osu.Game.Database; using osu.Game.IO; using osu.Game.Screens.Play.HUD; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; namespace osu.Game.Skinning { @@ -77,7 +82,7 @@ namespace osu.Game.Skinning (storage as ResourceStore)?.AddExtension("ogg"); Samples = samples; - Textures = new TextureStore(resources.Renderer, resources.CreateTextureLoaderStore(storage)); + Textures = new TextureStore(resources.Renderer, new SquishingTextureLoaderStore(resources.CreateTextureLoaderStore(storage))); } else { @@ -210,5 +215,54 @@ namespace osu.Game.Skinning } #endregion + + public class SquishingTextureLoaderStore : IResourceStore + { + private readonly IResourceStore textureStore; + + public SquishingTextureLoaderStore(IResourceStore textureStore) + { + this.textureStore = textureStore; + } + + public void Dispose() + { + textureStore.Dispose(); + } + + public TextureUpload Get(string name) + { + var textureUpload = textureStore.Get(name); + + // NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp. + if (textureUpload.IsNull()) + return null!; + + // So there's a thing where some users have taken it upon themselves to create skin elements of insane dimensions. + // To the point where GPUs cannot load the textures (along with most image editor apps). + // To work around this, let's look out for any stupid images and shrink them down into a usable size. + const int max_supported_texture_size = 16384; + + if (textureUpload.Height > max_supported_texture_size || textureUpload.Width > max_supported_texture_size) + { + var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height); + + image.Mutate(i => i.Resize(new Size( + Math.Min(textureUpload.Width, max_supported_texture_size), + Math.Min(textureUpload.Height, max_supported_texture_size) + ))); + + return new TextureUpload(image); + } + + return textureUpload; + } + + public Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) => textureStore.GetAsync(name, cancellationToken); + + public Stream GetStream(string name) => textureStore.GetStream(name); + + public IEnumerable GetAvailableResources() => textureStore.GetAvailableResources(); + } } }