diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index feda251744..6a7fab86d6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.IO; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -173,7 +174,7 @@ namespace osu.Game.Tests.Visual.Gameplay string? filePath = null; // Files starting with _ are temporary, created by CreateFileSafely call. - AddUntilStep("wait for export file", () => filePath = LocalStorage.GetFiles("exports").SingleOrDefault(f => !f.StartsWith("_", StringComparison.Ordinal)), () => Is.Not.Null); + AddUntilStep("wait for export file", () => filePath = LocalStorage.GetFiles("exports").SingleOrDefault(f => !Path.GetFileName(f).StartsWith("_", StringComparison.Ordinal)), () => Is.Not.Null); AddAssert("filesize is non-zero", () => { using (var stream = LocalStorage.GetStream(filePath)) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerMaxDimensions.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerMaxDimensions.cs index a8ed44c7f8..68443b234b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerMaxDimensions.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerMaxDimensions.cs @@ -3,14 +3,20 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; using osu.Framework.Testing; using osu.Game.IO; using osu.Game.Rulesets; using osu.Game.Screens.Play; using osu.Game.Skinning; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; namespace osu.Game.Tests.Visual.Gameplay { @@ -23,6 +29,9 @@ namespace osu.Game.Tests.Visual.Gameplay /// public partial class TestScenePlayerMaxDimensions : TestSceneAllRulesetPlayers { + // scale textures to 4 times their size. + private const int scale_factor = 4; + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); @@ -63,18 +72,66 @@ namespace osu.Game.Tests.Visual.Gameplay remove { } } - public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) - { - var texture = base.GetTexture(componentName, wrapModeS, wrapModeT); - - if (texture != null) - texture.ScaleAdjust /= 8f; - - return texture; - } - public ISkin FindProvider(Func lookupFunction) => this; public IEnumerable AllSources => new[] { this }; + + protected override IResourceStore CreateTextureLoaderStore(IStorageResourceProvider resources, IResourceStore storage) + => new UpscaledTextureLoaderStore(base.CreateTextureLoaderStore(resources, storage)); + + private class UpscaledTextureLoaderStore : IResourceStore + { + private readonly IResourceStore? textureStore; + + public UpscaledTextureLoaderStore(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 == null) + return null!; + + return upscale(textureUpload); + } + + public async Task GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) + { + // NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp. + if (textureStore == null) + return null!; + + var textureUpload = await textureStore.GetAsync(name, cancellationToken).ConfigureAwait(false); + + if (textureUpload == null) + return null!; + + return await Task.Run(() => upscale(textureUpload), cancellationToken).ConfigureAwait(false); + } + + private TextureUpload upscale(TextureUpload textureUpload) + { + var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height); + + // The original texture upload will no longer be returned or used. + textureUpload.Dispose(); + + image.Mutate(i => i.Resize(new Size(textureUpload.Width, textureUpload.Height) * scale_factor)); + return new TextureUpload(image); + } + + public Stream? GetStream(string name) => textureStore?.GetStream(name); + + public IEnumerable GetAvailableResources() => textureStore?.GetAvailableResources() ?? Array.Empty(); + } } } } diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index dde6c1fa29..868f36fb34 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osuTK; @@ -112,9 +113,11 @@ namespace osu.Game.Skinning if (texture.DisplayWidth <= maxSize.X && texture.DisplayHeight <= maxSize.Y) return texture; - // use scale adjust property for downscaling the texture in order to meet the specified maximum dimensions. - texture.ScaleAdjust *= Math.Max(texture.DisplayWidth / maxSize.X, texture.DisplayHeight / maxSize.Y); - return texture; + maxSize *= texture.ScaleAdjust; + + var croppedTexture = texture.Crop(new RectangleF(texture.Width / 2f - maxSize.X / 2f, texture.Height / 2f - maxSize.Y / 2f, maxSize.X, maxSize.Y)); + croppedTexture.ScaleAdjust = texture.ScaleAdjust; + return croppedTexture; } public static bool HasFont(this ISkin source, LegacyFont font) diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index ccf49d722f..1e312142d7 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -88,7 +88,7 @@ namespace osu.Game.Skinning } Samples = samples; - Textures = new TextureStore(resources.Renderer, new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage))); + Textures = new TextureStore(resources.Renderer, CreateTextureLoaderStore(resources, storage)); } else { @@ -171,6 +171,9 @@ namespace osu.Game.Skinning } } + protected virtual IResourceStore CreateTextureLoaderStore(IStorageResourceProvider resources, IResourceStore storage) + => new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage)); + protected virtual void ParseConfigurationStream(Stream stream) { using (LineBufferedReader reader = new LineBufferedReader(stream, true))