2019-07-15 02:46:41 +00:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2019-01-24 08:43:03 +00:00
// See the LICENCE file in the repository root for full licence text.
2018-04-13 09:19:50 +00:00
2022-06-17 07:37:17 +00:00
#nullable disable
2021-06-08 20:26:15 +00:00
using System ;
2022-01-11 12:22:16 +00:00
using System.Diagnostics ;
2016-11-23 02:59:50 +00:00
using osu.Framework.Allocation ;
2016-09-30 09:45:55 +00:00
using osu.Framework.Graphics ;
2016-11-23 02:59:50 +00:00
using osu.Framework.Graphics.Containers ;
2016-09-30 09:45:55 +00:00
using osu.Framework.Graphics.Sprites ;
2018-09-06 04:15:43 +00:00
using osu.Framework.Graphics.Textures ;
2019-07-02 08:45:46 +00:00
using osu.Framework.Graphics.Transforms ;
using osuTK ;
2018-04-13 09:19:50 +00:00
2016-11-23 02:59:50 +00:00
namespace osu.Game.Graphics.Backgrounds
2016-09-30 09:45:55 +00:00
{
2019-07-02 08:45:46 +00:00
/// <summary>
2019-07-02 08:47:19 +00:00
/// A background which offers blurring via a <see cref="BufferedContainer"/> on demand.
2019-07-02 08:45:46 +00:00
/// </summary>
2021-06-08 20:26:15 +00:00
public partial class Background : CompositeDrawable , IEquatable < Background >
2016-09-30 09:45:55 +00:00
{
2019-07-15 02:45:15 +00:00
public readonly Sprite Sprite ;
2018-04-13 09:19:50 +00:00
2017-03-23 04:41:50 +00:00
private readonly string textureName ;
2018-04-13 09:19:50 +00:00
2019-07-02 08:45:46 +00:00
private BufferedContainer bufferedContainer ;
2016-11-19 16:39:43 +00:00
public Background ( string textureName = @"" )
2016-10-01 09:40:14 +00:00
{
2016-10-05 07:35:10 +00:00
this . textureName = textureName ;
2016-10-01 09:40:14 +00:00
RelativeSizeAxes = Axes . Both ;
2018-04-13 09:19:50 +00:00
2019-07-02 08:45:46 +00:00
AddInternal ( Sprite = new Sprite
2016-09-30 09:45:55 +00:00
{
2017-06-28 09:24:23 +00:00
RelativeSizeAxes = Axes . Both ,
2016-09-30 09:45:55 +00:00
Anchor = Anchor . Centre ,
Origin = Anchor . Centre ,
2016-11-23 04:18:22 +00:00
FillMode = FillMode . Fill ,
2016-09-30 09:45:55 +00:00
} ) ;
}
2018-04-13 09:19:50 +00:00
2016-11-12 17:34:36 +00:00
[BackgroundDependencyLoader]
2018-08-30 22:04:40 +00:00
private void load ( LargeTextureStore textures )
2016-11-12 17:34:36 +00:00
{
2016-11-19 16:39:43 +00:00
if ( ! string . IsNullOrEmpty ( textureName ) )
2018-08-30 22:04:40 +00:00
Sprite . Texture = textures . Get ( textureName ) ;
2016-11-12 17:34:36 +00:00
}
2019-07-02 08:45:46 +00:00
2022-01-11 12:22:16 +00:00
public Vector2 BlurSigma = > Vector2 . Divide ( bufferedContainer ? . BlurSigma ? ? Vector2 . Zero , blurScale ) ;
2019-07-02 08:45:46 +00:00
/// <summary>
/// Smoothly adjusts <see cref="IBufferedContainer.BlurSigma"/> over time.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public void BlurTo ( Vector2 newBlurSigma , double duration = 0 , Easing easing = Easing . None )
{
2019-07-15 02:46:41 +00:00
if ( bufferedContainer = = null & & newBlurSigma ! = Vector2 . Zero )
2019-07-02 08:45:46 +00:00
{
2022-08-29 06:49:28 +00:00
RemoveInternal ( Sprite , false ) ;
2019-07-02 08:45:46 +00:00
2021-11-05 06:54:27 +00:00
AddInternal ( bufferedContainer = new BufferedContainer ( cachedFrameBuffer : true )
2019-07-02 08:45:46 +00:00
{
RelativeSizeAxes = Axes . Both ,
2019-09-04 10:38:12 +00:00
RedrawOnScale = false ,
2019-07-02 08:45:46 +00:00
Child = Sprite
} ) ;
}
2019-11-27 06:04:09 +00:00
if ( bufferedContainer ! = null )
2022-01-11 12:22:16 +00:00
transformBlurSigma ( newBlurSigma , duration , easing ) ;
}
private void transformBlurSigma ( Vector2 newBlurSigma , double duration , Easing easing )
= > this . TransformTo ( nameof ( blurSigma ) , newBlurSigma , duration , easing ) ;
private Vector2 blurSigmaBacking = Vector2 . Zero ;
private Vector2 blurScale = Vector2 . One ;
private Vector2 blurSigma
{
get = > blurSigmaBacking ;
set
{
Debug . Assert ( bufferedContainer ! = null ) ;
blurSigmaBacking = value ;
blurScale = new Vector2 ( calculateBlurDownscale ( value . X ) , calculateBlurDownscale ( value . Y ) ) ;
bufferedContainer . FrameBufferScale = blurScale ;
bufferedContainer . BlurSigma = value * blurScale ; // If the image is scaled down, the blur radius also needs to be reduced to cover the same pixel block.
}
}
/// <summary>
/// Determines a factor to downscale the background based on a given blur sigma, in order to reduce the computational complexity of blurs.
/// </summary>
/// <param name="sigma">The blur sigma.</param>
/// <returns>The scale-down factor.</returns>
private float calculateBlurDownscale ( float sigma )
{
// If we're blurring within one pixel, scaling down will always result in an undesirable loss of quality.
// The algorithm below would also cause this value to go above 1, which is likewise undesirable.
if ( sigma < = 1 )
return 1 ;
// A good value is one where the loss in quality as a result of downscaling the image is not easily perceivable.
// The constants here have been experimentally chosen to yield nice transitions by approximating a log curve through the points {{ 1, 1 }, { 4, 0.75 }, { 16, 0.5 }, { 32, 0.25 }}.
float scale = - 0.18f * MathF . Log ( 0.004f * sigma ) ;
2019-11-27 06:04:09 +00:00
2022-01-11 12:22:16 +00:00
// To reduce shimmering, the scaling transitions are limited to happen only in increments of 0.2.
return MathF . Round ( scale / 0.2f , MidpointRounding . AwayFromZero ) * 0.2f ;
2019-07-02 08:45:46 +00:00
}
2021-06-08 20:26:15 +00:00
public virtual bool Equals ( Background other )
{
if ( ReferenceEquals ( null , other ) ) return false ;
if ( ReferenceEquals ( this , other ) ) return true ;
return other . GetType ( ) = = GetType ( )
& & other . textureName = = textureName ;
}
2016-09-30 09:45:55 +00:00
}
}