From 343c560b1b92e7e8fb603915816f0f8aad2116de Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 18 Oct 2022 03:33:03 -0700 Subject: [PATCH 1/4] Remove smoke point maximum/cap --- .../Skinning/SmokeSegment.cs | 144 +++++++++--------- 1 file changed, 75 insertions(+), 69 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index aba4d0ff63..6aee9ca2df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -22,8 +23,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { public abstract class SmokeSegment : Drawable, ITexturedShaderDrawable { - private const int max_point_count = 18_000; - // fade anim values private const double initial_fade_out_duration = 4000; @@ -85,12 +84,6 @@ protected override void LoadComplete() totalDistance = pointInterval; } - private Vector2 nextPointDirection() - { - float angle = RNG.NextSingle(0, 2 * MathF.PI); - return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); - } - public void AddPosition(Vector2 position, double time) { lastPosition ??= position; @@ -107,33 +100,27 @@ public void AddPosition(Vector2 position, double time) Vector2 pointPos = (pointInterval - (totalDistance - delta)) * increment + (Vector2)lastPosition; increment *= pointInterval; - if (SmokePoints.Count > 0 && SmokePoints[^1].Time > time) - { - int index = ~SmokePoints.BinarySearch(new SmokePoint { Time = time }, new SmokePoint.UpperBoundComparer()); - SmokePoints.RemoveRange(index, SmokePoints.Count - index); - } - totalDistance %= pointInterval; - for (int i = 0; i < count; i++) + if (SmokePoints.Count == 0 || SmokePoints[^1].Time <= time) { - SmokePoints.Add(new SmokePoint + for (int i = 0; i < count; i++) { - Position = pointPos, - Time = time, - Direction = nextPointDirection(), - }); + SmokePoints.Add(new SmokePoint + { + Position = pointPos, + Time = time, + Angle = RNG.NextSingle(0, 2 * MathF.PI), + }); - pointPos += increment; + pointPos += increment; + } } Invalidate(Invalidation.DrawNode); } lastPosition = position; - - if (SmokePoints.Count >= max_point_count) - FinishDrawing(time); } public void FinishDrawing(double time) @@ -157,7 +144,7 @@ protected struct SmokePoint { public Vector2 Position; public double Time; - public Vector2 Direction; + public float Angle; public struct UpperBoundComparer : IComparer { @@ -171,6 +158,17 @@ public int Compare(SmokePoint x, SmokePoint target) return x.Time > target.Time ? 1 : -1; } } + + public struct LowerBoundComparer : IComparer + { + public int Compare(SmokePoint x, SmokePoint target) + { + // Similar logic as UpperBoundComparer, except returned index will always be + // the first element larger or equal + + return x.Time < target.Time ? -1 : 1; + } + } } protected class SmokeDrawNode : TexturedShaderDrawNode @@ -187,11 +185,11 @@ protected class SmokeDrawNode : TexturedShaderDrawNode private Vector2 drawSize; private Texture? texture; private int rotationSeed; - private int rotationIndex; + private int firstVisibleIndex; // anim calculation vars (color, scale, direction) private double initialFadeOutDurationTrunc; - private double firstVisiblePointTime; + private double firstVisiblePointTimeAfterSmokeEnded; private double initialFadeOutTime; private double reFadeInTime; @@ -206,9 +204,6 @@ public override void ApplyState() { base.ApplyState(); - points.Clear(); - points.AddRange(Source.SmokePoints); - radius = Source.radius; drawSize = Source.DrawSize; texture = Source.Texture; @@ -220,11 +215,18 @@ public override void ApplyState() rotationSeed = Source.rotationSeed; initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; + firstVisiblePointTimeAfterSmokeEnded = SmokeEndTime - initialFadeOutDurationTrunc; - initialFadeOutTime = CurrentTime; - reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / re_fade_in_speed); - finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / final_fade_out_speed); + initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); + reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / re_fade_in_speed); + finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / final_fade_out_speed); + + double firstVisibleTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc; + firstVisibleIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisibleTime }, new SmokePoint.LowerBoundComparer()); + int futureIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer()); + + points.Clear(); + points.AddRange(Source.SmokePoints.Skip(firstVisibleIndex).Take(futureIndex - firstVisibleIndex)); } public sealed override void Draw(IRenderer renderer) @@ -234,9 +236,12 @@ public sealed override void Draw(IRenderer renderer) if (points.Count == 0) return; - rotationIndex = 0; - - quadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); + quadBatch ??= renderer.CreateQuadBatch(200, 4); + if (points.Count > quadBatch.Size * 4 && quadBatch.Size != 10922) + { + int batchSize = Math.Min((int)(quadBatch.Size * 1.5f), 10922); + quadBatch = renderer.CreateQuadBatch(batchSize, 4); + } texture ??= renderer.WhitePixel; RectangleF textureRect = texture.GetTextureRect(); @@ -248,8 +253,8 @@ public sealed override void Draw(IRenderer renderer) shader.Bind(); texture.Bind(); - foreach (var point in points) - drawPointQuad(point, textureRect); + for (int i = 0; i < points.Count; i++) + drawPointQuad(points[i], textureRect, i + firstVisibleIndex); shader.Unbind(); renderer.PopLocalMatrix(); @@ -263,30 +268,31 @@ protected virtual Color4 PointColour(SmokePoint point) { var color = Color4.White; - double timeDoingInitialFadeOut = Math.Min(initialFadeOutTime, SmokeEndTime) - point.Time; - - if (timeDoingInitialFadeOut > 0) + double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; + if (timeDoingFinalFadeOut > 0 && point.Time > firstVisiblePointTimeAfterSmokeEnded) { - float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); - color.A = (1 - fraction) * initial_alpha; + float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); + fraction = MathF.Pow(fraction, 5); + color.A = (1 - fraction) * re_fade_in_alpha; } - - if (color.A > 0) + else { - double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; - double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; - - if (timeDoingFinalFadeOut > 0) + double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; + if (timeDoingInitialFadeOut > 0) { - float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); - fraction = MathF.Pow(fraction, 5); - color.A = (1 - fraction) * re_fade_in_alpha; + float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); + color.A = (1 - fraction) * initial_alpha; } - else if (timeDoingReFadeIn > 0) + + if (point.Time > firstVisiblePointTimeAfterSmokeEnded) { - float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); - fraction = 1 - MathF.Pow(1 - fraction, 5); - color.A = fraction * (re_fade_in_alpha - color.A) + color.A; + double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; + if (timeDoingReFadeIn > 0) + { + float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + color.A = fraction * (re_fade_in_alpha - color.A) + color.A; + } } } @@ -301,33 +307,33 @@ protected virtual float PointScale(SmokePoint point) return fraction * (final_scale - initial_scale) + initial_scale; } - protected virtual Vector2 PointDirection(SmokePoint point) + protected virtual Vector2 PointDirection(SmokePoint point, int index) { - 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; + float angle = fraction * getRotation(index) + point.Angle; return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } - private float nextRotation() => max_rotation * (StatelessRNG.NextSingle(rotationSeed, rotationIndex++) * 2 - 1); + private float getRotation(int index) => max_rotation * (StatelessRNG.NextSingle(rotationSeed, index) * 2 - 1); - private void drawPointQuad(SmokePoint point, RectangleF textureRect) + private void drawPointQuad(SmokePoint point, RectangleF textureRect, int index) { Debug.Assert(quadBatch != null); var colour = PointColour(point); - float scale = PointScale(point); - var dir = PointDirection(point); - var ortho = dir.PerpendicularLeft; - - if (colour.A == 0 || scale == 0) + if (colour.A == 0) return; + float scale = PointScale(point); + if (scale == 0) + return; + + var dir = PointDirection(point, index); + var ortho = dir.PerpendicularLeft; + var localTopLeft = point.Position + (radius * scale * (-ortho - dir)); var localTopRight = point.Position + (radius * scale * (-ortho + dir)); var localBotLeft = point.Position + (radius * scale * (ortho - dir)); From a9b8ba94fa923eb54ca4304504f1e2e6cf416f04 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 18 Oct 2022 22:59:58 -0700 Subject: [PATCH 2/4] Add necessary newlines --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 6aee9ca2df..5e72f165df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -237,11 +237,13 @@ public sealed override void Draw(IRenderer renderer) return; quadBatch ??= renderer.CreateQuadBatch(200, 4); + if (points.Count > quadBatch.Size * 4 && quadBatch.Size != 10922) { int batchSize = Math.Min((int)(quadBatch.Size * 1.5f), 10922); quadBatch = renderer.CreateQuadBatch(batchSize, 4); } + texture ??= renderer.WhitePixel; RectangleF textureRect = texture.GetTextureRect(); @@ -269,6 +271,7 @@ protected virtual Color4 PointColour(SmokePoint point) var color = Color4.White; double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; + if (timeDoingFinalFadeOut > 0 && point.Time > firstVisiblePointTimeAfterSmokeEnded) { float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); @@ -278,6 +281,7 @@ protected virtual Color4 PointColour(SmokePoint point) else { double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; + if (timeDoingInitialFadeOut > 0) { float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); @@ -287,6 +291,7 @@ protected virtual Color4 PointColour(SmokePoint point) if (point.Time > firstVisiblePointTimeAfterSmokeEnded) { double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; + if (timeDoingReFadeIn > 0) { float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); From 50ab9bff8b8609b1b3438c314d2b957c23578e9d Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 18 Oct 2022 23:05:09 -0700 Subject: [PATCH 3/4] Rename for consistency --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 5e72f165df..23bfea5240 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -185,7 +185,7 @@ protected class SmokeDrawNode : TexturedShaderDrawNode private Vector2 drawSize; private Texture? texture; private int rotationSeed; - private int firstVisibleIndex; + private int firstVisiblePointIndex; // anim calculation vars (color, scale, direction) private double initialFadeOutDurationTrunc; @@ -221,12 +221,12 @@ public override void ApplyState() reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / re_fade_in_speed); finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / final_fade_out_speed); - double firstVisibleTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc; - firstVisibleIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisibleTime }, new SmokePoint.LowerBoundComparer()); - int futureIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer()); + double firstVisiblePointTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc; + firstVisiblePointIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisiblePointTime }, new SmokePoint.LowerBoundComparer()); + int futurePointIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer()); points.Clear(); - points.AddRange(Source.SmokePoints.Skip(firstVisibleIndex).Take(futureIndex - firstVisibleIndex)); + points.AddRange(Source.SmokePoints.Skip(firstVisiblePointIndex).Take(futurePointIndex - firstVisiblePointIndex)); } public sealed override void Draw(IRenderer renderer) @@ -256,7 +256,7 @@ public sealed override void Draw(IRenderer renderer) texture.Bind(); for (int i = 0; i < points.Count; i++) - drawPointQuad(points[i], textureRect, i + firstVisibleIndex); + drawPointQuad(points[i], textureRect, i + firstVisiblePointIndex); shader.Unbind(); renderer.PopLocalMatrix(); @@ -272,7 +272,7 @@ protected virtual Color4 PointColour(SmokePoint point) double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; - if (timeDoingFinalFadeOut > 0 && point.Time > firstVisiblePointTimeAfterSmokeEnded) + if (timeDoingFinalFadeOut > 0 && point.Time >= firstVisiblePointTimeAfterSmokeEnded) { float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); fraction = MathF.Pow(fraction, 5); From 23b7b9013e65f0b9c7828ac5d1cbac4b18d98dc0 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Thu, 20 Oct 2022 23:37:05 -0700 Subject: [PATCH 4/4] Change smoke quadbatch growth factor to 2 from 1.5 --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 23bfea5240..46c8e7c02a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -238,9 +238,9 @@ public sealed override void Draw(IRenderer renderer) quadBatch ??= renderer.CreateQuadBatch(200, 4); - if (points.Count > quadBatch.Size * 4 && quadBatch.Size != 10922) + if (points.Count > quadBatch.Size && quadBatch.Size != IRenderer.MAX_QUADS) { - int batchSize = Math.Min((int)(quadBatch.Size * 1.5f), 10922); + int batchSize = Math.Min(quadBatch.Size * 2, IRenderer.MAX_QUADS); quadBatch = renderer.CreateQuadBatch(batchSize, 4); }