mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 16:32:54 +08:00
Merge pull request #24975 from frenzibyte/crop-gameplay-textures
Crop oversized gameplay textures instead of downscaling them
This commit is contained in:
commit
b0176dcbf7
@ -3,14 +3,20 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using SixLabors.ImageSharp;
|
||||||
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
@ -23,6 +29,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public partial class TestScenePlayerMaxDimensions : TestSceneAllRulesetPlayers
|
public partial class TestScenePlayerMaxDimensions : TestSceneAllRulesetPlayers
|
||||||
{
|
{
|
||||||
|
// scale textures to 4 times their size.
|
||||||
|
private const int scale_factor = 4;
|
||||||
|
|
||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
{
|
{
|
||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
@ -63,18 +72,66 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
remove { }
|
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<ISkin, bool> lookupFunction) => this;
|
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => this;
|
||||||
public IEnumerable<ISkin> AllSources => new[] { this };
|
public IEnumerable<ISkin> AllSources => new[] { this };
|
||||||
|
|
||||||
|
protected override IResourceStore<TextureUpload> CreateTextureLoaderStore(IStorageResourceProvider resources, IResourceStore<byte[]> storage)
|
||||||
|
=> new UpscaledTextureLoaderStore(base.CreateTextureLoaderStore(resources, storage));
|
||||||
|
|
||||||
|
private class UpscaledTextureLoaderStore : IResourceStore<TextureUpload>
|
||||||
|
{
|
||||||
|
private readonly IResourceStore<TextureUpload>? textureStore;
|
||||||
|
|
||||||
|
public UpscaledTextureLoaderStore(IResourceStore<TextureUpload>? 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<TextureUpload> 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<string> GetAvailableResources() => textureStore?.GetAvailableResources() ?? Array.Empty<string>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -112,9 +113,11 @@ namespace osu.Game.Skinning
|
|||||||
if (texture.DisplayWidth <= maxSize.X && texture.DisplayHeight <= maxSize.Y)
|
if (texture.DisplayWidth <= maxSize.X && texture.DisplayHeight <= maxSize.Y)
|
||||||
return texture;
|
return texture;
|
||||||
|
|
||||||
// use scale adjust property for downscaling the texture in order to meet the specified maximum dimensions.
|
maxSize *= texture.ScaleAdjust;
|
||||||
texture.ScaleAdjust *= Math.Max(texture.DisplayWidth / maxSize.X, texture.DisplayHeight / maxSize.Y);
|
|
||||||
return texture;
|
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)
|
public static bool HasFont(this ISkin source, LegacyFont font)
|
||||||
|
@ -88,7 +88,7 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
|
|
||||||
Samples = samples;
|
Samples = samples;
|
||||||
Textures = new TextureStore(resources.Renderer, new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage)));
|
Textures = new TextureStore(resources.Renderer, CreateTextureLoaderStore(resources, storage));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -171,6 +171,9 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual IResourceStore<TextureUpload> CreateTextureLoaderStore(IStorageResourceProvider resources, IResourceStore<byte[]> storage)
|
||||||
|
=> new MaxDimensionLimitedTextureLoaderStore(resources.CreateTextureLoaderStore(storage));
|
||||||
|
|
||||||
protected virtual void ParseConfigurationStream(Stream stream)
|
protected virtual void ParseConfigurationStream(Stream stream)
|
||||||
{
|
{
|
||||||
using (LineBufferedReader reader = new LineBufferedReader(stream, true))
|
using (LineBufferedReader reader = new LineBufferedReader(stream, true))
|
||||||
|
Loading…
Reference in New Issue
Block a user