diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index e7f526da31..0ba0143466 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default @@ -40,12 +41,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default fadeOutTime = SmokeStartTime + fade_out_speed * (CurrentTime - (SmokeEndTime + fade_out_delay)); } - protected override Color4 ColorAtTime(double pointTime) + protected override Color4 PointColor(SmokePoint point) { var color = Color4.White; color.A = alpha; - double timeDoingFadeOut = fadeOutTime - pointTime; + double timeDoingFadeOut = fadeOutTime - point.Time; if (timeDoingFadeOut > 0) { @@ -56,6 +57,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default return color; } + + protected override float PointScale(SmokePoint point) + { + throw new NotImplementedException(); + } + + protected override Vector2 PointDirection(SmokePoint point) + { + throw new NotImplementedException(); + } } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 23ab2d186f..093d8f87eb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -4,29 +4,59 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; +using osu.Framework.Utils; using osu.Game.Skinning; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacySmoke : Smoke { - private const double initial_fade_out_duration = 2500; + // fade values + private const double initial_fade_out_duration = 4000; private const double re_fade_in_speed = 3; private const double re_fade_in_duration = 50; - private const double final_fade_out_duration = 7500; + private const double final_fade_out_speed = 2; + private const double final_fade_out_duration = 8000; - private const float initial_alpha = 0.8f; - private const float re_fade_in_alpha = 1.4f; + private const float initial_alpha = 0.6f; + private const float re_fade_in_alpha = 1f; + + // scale values + private const double scale_duration = 1200; + + private const float initial_scale = 0.65f; + private const float final_scale = 1f; + + // rotation values + private const double rotation_duration = 500; + + private const float max_rotation = 0.25f; + + private int rotationSeed = RNG.Next(); + + protected int RotationSeed + { + get => rotationSeed; + set + { + if (rotationSeed == value) + return; + + rotationSeed = value; + Invalidate(Invalidation.DrawNode); + } + } protected override double LifetimeAfterSmokeEnd { get { double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - return final_fade_out_duration + initialFadeOutDurationTrunc * (1 + re_fade_in_speed); + return final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; } } @@ -49,11 +79,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected class LegacySmokeDrawNode : SmokeDrawNode { + protected new LegacySmoke Source => (LegacySmoke)base.Source; + private double initialFadeOutDurationTrunc; private double initialFadeOutTime; private double reFadeInTime; private double finalFadeOutTime; + private int rotationSeed; + private Random rotationRNG = new Random(); + public LegacySmokeDrawNode(ITexturedShaderDrawable source) : base(source) { @@ -64,34 +99,35 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy base.ApplyState(); initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + rotationSeed = Source.RotationSeed; } protected override void UpdateDrawVariables(IRenderer renderer) { base.UpdateDrawVariables(renderer); + rotationRNG = new Random(rotationSeed); initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); reFadeInTime = re_fade_in_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc; - finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); + finalFadeOutTime = final_fade_out_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); } - protected override Color4 ColorAtTime(double pointTime) + protected override Color4 PointColor(SmokePoint point) { var color = Color4.White; - double timeDoingInitialFadeOut = initialFadeOutTime - pointTime; + double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; if (timeDoingInitialFadeOut > 0) { float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); - fraction = MathF.Pow(fraction, 5); color.A = (1 - fraction) * initial_alpha; } if (color.A > 0) { - double timeDoingReFadeIn = reFadeInTime - pointTime; - double timeDoingFinalFadeOut = finalFadeOutTime - pointTime; + double timeDoingReFadeIn = reFadeInTime - point.Time; + double timeDoingFinalFadeOut = finalFadeOutTime - point.Time; if (timeDoingFinalFadeOut > 0) { @@ -109,6 +145,31 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return color; } + + protected override float PointScale(SmokePoint point) + { + double timeDoingScale = CurrentTime - point.Time; + float fraction = Math.Clamp((float)(timeDoingScale / scale_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + return fraction * (final_scale - initial_scale) + initial_scale; + } + + protected override Vector2 PointDirection(SmokePoint point) + { + float initialAngle = MathF.Atan2(point.Direction.Y, point.Direction.X); + float finalAngle = initialAngle + nextRotation(); + + double timeDoingRotation = CurrentTime - point.Time; + float fraction = Math.Clamp((float)(timeDoingRotation / rotation_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + float angle = fraction * (finalAngle - initialAngle) + initialAngle; + + return toVector2(angle); + } + + private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1); + + private Vector2 toVector2(float angle) => new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 382e54e2ab..b725cc028b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -42,21 +42,6 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - private int rotationSeed = RNG.Next(); - - protected int RotationSeed - { - get => rotationSeed; - set - { - if (rotationSeed == value) - return; - - rotationSeed = value; - Invalidate(Invalidation.DrawNode); - } - } - private Texture? texture; protected Texture? Texture @@ -195,6 +180,12 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeStartTime = Time.Current; } + private Vector2 nextPointDirection() + { + float angle = RNG.NextSingle(0, 2 * MathF.PI); + return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); + } + private void onSmokeMoved(Vector2 position, double time) { if (!IsActive) @@ -229,6 +220,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { Position = pointPos, Time = time, + Direction = nextPointDirection(), }); pointPos += increment; @@ -303,6 +295,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { public Vector2 Position; public double Time; + public Vector2 Direction; public struct UpperBoundComparer : IComparer { @@ -339,9 +332,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private IFrameBasedClock? clock; - private int rotationSeed; - private Random rotationRNG = new Random(); - protected SmokeDrawNode(ITexturedShaderDrawable source) : base(source) { @@ -362,8 +352,6 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeStartTime = Source.SmokeStartTime; SmokeEndTime = Source.SmokeEndTime; - - rotationSeed = Source.RotationSeed; } public sealed override void Draw(IRenderer renderer) @@ -377,6 +365,9 @@ namespace osu.Game.Rulesets.Osu.Skinning Texture ??= renderer.WhitePixel; var shader = GetAppropriateShader(renderer); + + renderer.SetBlend(BlendingParameters.Additive); + shader.Bind(); Texture.Bind(); @@ -390,7 +381,11 @@ namespace osu.Game.Rulesets.Osu.Skinning ? ((SRGBColour)DrawColourInfo.Colour).Linear : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, DrawSize)).Linear; - protected abstract Color4 ColorAtTime(double pointTime); + protected abstract Color4 PointColor(SmokePoint point); + + protected abstract float PointScale(SmokePoint point); + + protected abstract Vector2 PointDirection(SmokePoint point); protected virtual void UpdateDrawVariables(IRenderer renderer) { @@ -399,7 +394,6 @@ namespace osu.Game.Rulesets.Osu.Skinning CurrentTime = clock.CurrentTime; TextureRect = Texture.GetTextureRect(); - rotationRNG = new Random(rotationSeed); } protected virtual void UpdateVertexBuffer() @@ -408,24 +402,19 @@ namespace osu.Game.Rulesets.Osu.Skinning drawPointQuad(point); } - private Vector2 nextTextureDirection() - { - float angle = (float)rotationRNG.NextDouble() * 2 * MathF.PI; - return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); - } - private void drawPointQuad(SmokePoint point) { Debug.Assert(QuadBatch != null); - var color = ColorAtTime(point.Time); - var dir = nextTextureDirection(); + var color = PointColor(point); + float scale = PointScale(point); + var dir = PointDirection(point); var ortho = dir.PerpendicularLeft; - var localTopLeft = point.Position + (Radius * (-ortho - dir)) - PositionOffset; - var localTopRight = point.Position + (Radius * (-ortho + dir)) - PositionOffset; - var localBotLeft = point.Position + (Radius * (ortho - dir)) - PositionOffset; - var localBotRight = point.Position + (Radius * (ortho + dir)) - PositionOffset; + var localTopLeft = point.Position + (Radius * scale * (-ortho - dir)) - PositionOffset; + var localTopRight = point.Position + (Radius * scale * (-ortho + dir)) - PositionOffset; + var localBotLeft = point.Position + (Radius * scale * (ortho - dir)) - PositionOffset; + var localBotRight = point.Position + (Radius * scale * (ortho + dir)) - PositionOffset; QuadBatch.Add(new TexturedVertex2D {