protected override void Update()
        {
            base.Update();

            if (!Precision.AlmostEquals(counter.DrawWidth, aimWidth))
            {
                ClearTransforms();

                if (aimWidth == 0)
                {
                    Size = counter.DrawSize;
                }
                else if (Precision.AlmostBigger(counter.DrawWidth, aimWidth))
                {
                    this.ResizeTo(counter.DrawSize, 200, Easing.OutQuint);
                }
                else
                {
                    this.Delay(500).ResizeTo(counter.DrawSize, 200, Easing.InOutSine);
                }

                aimWidth = counter.DrawWidth;
            }

            if (Clock.CurrentTime - lastUpdateLocalTime > 1000.0 / updates_per_second)
            {
                updateDisplay();
            }
        }
Exemple #2
0
        protected override bool OnDrag(InputState state)
        {
            Trace.Assert(isDragging, "We should never receive OnDrag if we are not dragging.");

            double currentTime = Time.Current;
            double timeDelta   = currentTime - lastDragTime;
            double decay       = Math.Pow(0.95, timeDelta);

            averageDragTime  = averageDragTime * decay + timeDelta;
            averageDragDelta = averageDragDelta * decay - state.Mouse.Delta[scrollDim];

            lastDragTime = currentTime;

            Vector2 childDelta = ToLocalSpace(state.Mouse.NativeState.Position) - ToLocalSpace(state.Mouse.NativeState.LastPosition);

            float scrollOffset        = -childDelta[scrollDim];
            float clampedScrollOffset = clamp(target + scrollOffset) - clamp(target);

            Trace.Assert(Precision.AlmostBigger(Math.Abs(scrollOffset), clampedScrollOffset * Math.Sign(scrollOffset)));

            // If we are dragging past the extent of the scrollable area, half the offset
            // such that the user can feel it.
            scrollOffset = clampedScrollOffset + (scrollOffset - clampedScrollOffset) / 2;

            offset(scrollOffset, false);
            return(true);
        }
        /// <summary>
        /// Retrieves the <see cref="DifficultyRating"/> that describes a star rating.
        /// </summary>
        /// <remarks>
        /// For more information, see: https://osu.ppy.sh/help/wiki/Difficulties
        /// </remarks>
        /// <param name="starRating">The star rating.</param>
        /// <returns>The <see cref="DifficultyRating"/> that best describes <paramref name="starRating"/>.</returns>
        public static DifficultyRating GetDifficultyRating(double starRating)
        {
            if (Precision.AlmostBigger(starRating, 6.5, 0.005))
            {
                return(DifficultyRating.ExpertPlus);
            }

            if (Precision.AlmostBigger(starRating, 5.3, 0.005))
            {
                return(DifficultyRating.Expert);
            }

            if (Precision.AlmostBigger(starRating, 4.0, 0.005))
            {
                return(DifficultyRating.Insane);
            }

            if (Precision.AlmostBigger(starRating, 2.7, 0.005))
            {
                return(DifficultyRating.Hard);
            }

            if (Precision.AlmostBigger(starRating, 2.0, 0.005))
            {
                return(DifficultyRating.Normal);
            }

            return(DifficultyRating.Easy);
        }
Exemple #4
0
        protected override void Update()
        {
            base.Update();

            if (!Counting)
            {
                return;
            }

            displayFps = Interpolation.Damp(displayFps, clock.FramesPerSecond, 0.01, clock.ElapsedFrameTime / 1000);

            if (counter.DrawWidth != aimWidth)
            {
                ClearTransformations();

                if (aimWidth == 0)
                {
                    Size = counter.DrawSize;
                }
                else if (Precision.AlmostBigger(counter.DrawWidth, aimWidth))
                {
                    ResizeTo(counter.DrawSize, 200, EasingTypes.InOutSine);
                }
                else
                {
                    Delay(1500);
                    ResizeTo(counter.DrawSize, 500, EasingTypes.InOutSine);
                }

                aimWidth = counter.DrawWidth;
            }

            counter.Text = displayFps.ToString(@"0");
        }
Exemple #5
0
            protected override void Update()
            {
                base.Update();

                // the bounds below represent the horizontal range of scroll items to be considered fully visible/active, in the scroll's internal coordinate space.
                // note that clamping is applied to the left scroll bound to ensure scrolling past extents does not change the set of active columns.
                float leftVisibleBound  = Math.Clamp(Current, 0, ScrollableExtent);
                float rightVisibleBound = leftVisibleBound + DrawWidth;

                // if a movement is occurring at this time, the bounds below represent the full range of columns that the scroll movement will encompass.
                // this will be used to ensure that columns do not change state from active to inactive back and forth until they are fully scrolled past.
                float leftMovementBound  = Math.Min(Current, Target);
                float rightMovementBound = Math.Max(Current, Target) + DrawWidth;

                foreach (var column in Child)
                {
                    // DrawWidth/DrawPosition do not include shear effects, and we want to know the full extents of the columns post-shear,
                    // so we have to manually compensate.
                    var topLeft     = column.ToSpaceOfOtherDrawable(Vector2.Zero, ScrollContent);
                    var bottomRight = column.ToSpaceOfOtherDrawable(new Vector2(column.DrawWidth - column.DrawHeight * SHEAR, 0), ScrollContent);

                    bool isCurrentlyVisible = Precision.AlmostBigger(topLeft.X, leftVisibleBound) &&
                                              Precision.DefinitelyBigger(rightVisibleBound, bottomRight.X);
                    bool isBeingScrolledToward = Precision.AlmostBigger(topLeft.X, leftMovementBound) &&
                                                 Precision.DefinitelyBigger(rightMovementBound, bottomRight.X);

                    column.Active.Value = isCurrentlyVisible || isBeingScrolledToward;
                }
            }
                public override void Draw(Action <TexturedVertex2D> vertexAction)
                {
                    if (!textureReference.TryGetTarget(out var texture))
                    {
                        return;
                    }

                    if (!texture.Available)
                    {
                        return;
                    }

                    ulong delta = texture.BindCount - Source.lastBindCount;

                    Source.AverageUsagesPerFrame = Source.AverageUsagesPerFrame * 0.9f + delta * 0.1f;

                    drawColour = DrawColourInfo.Colour;
                    drawColour.ApplyChild(
                        Precision.AlmostBigger(Source.AverageUsagesPerFrame, 1)
                            ? Interpolation.ValueAt(Source.AverageUsagesPerFrame, Color4.DarkGray, Color4.Red, 0, 200)
                            : Color4.Transparent);

                    base.Draw(vertexAction);

                    // intentionally after draw to avoid counting our own bind.
                    Source.lastBindCount = texture.BindCount;
                }
Exemple #7
0
        /// <summary>
        /// Creates parts that have at least PartingDistance number of beats of a gap between the parts.
        /// </summary>
        /// <param name="beatmap">The beatmap to partition.</param>
        /// <param name="beatMode">Set to true if the beatmap uses beat time.</param>
        /// <returns>List of tuples with start time, end time.</returns>
        private List <Part> PartitionBeatmap(Beatmap beatmap, bool beatMode)
        {
            var parts = new List <Part>();

            int startIndex = 0;

            for (int i = 1; i < beatmap.HitObjects.Count; i++)
            {
                var gap = beatMode ?
                          beatmap.HitObjects[i].Time - beatmap.HitObjects[i - 1].GetEndTime(false) :
                          beatmap.BeatmapTiming.GetBeatLength(beatmap.HitObjects[i - 1].GetEndTime(), beatmap.HitObjects[i].Time);

                if (Precision.AlmostBigger(gap, PartingDistance))
                {
                    parts.Add(new Part(beatmap.HitObjects[startIndex].Time,
                                       beatmap.HitObjects[i - 1].GetEndTime(!beatMode),
                                       beatmap.HitObjects.GetRange(startIndex, i - startIndex)));

                    startIndex = i;
                }
            }
            parts.Add(new Part(beatmap.HitObjects[startIndex].Time,
                               beatmap.HitObjects[beatmap.HitObjects.Count - 1].GetEndTime(!beatMode),
                               beatmap.HitObjects.GetRange(startIndex, beatmap.HitObjects.Count - startIndex)));

            return(parts);
        }
        protected override void LoadComplete()
        {
            base.LoadComplete();

            double lastUpdate = 0;

            Scheduler.AddDelayed(() =>
                {
                    if (!Counting) return;

                    if (!Precision.AlmostEquals(counter.DrawWidth, aimWidth))
                    {
                        ClearTransforms();

                        if (aimWidth == 0)
                            Size = counter.DrawSize;
                        else if (Precision.AlmostBigger(counter.DrawWidth, aimWidth))
                            this.ResizeTo(counter.DrawSize, 200, Easing.InOutSine);
                        else
                            this.Delay(1500).ResizeTo(counter.DrawSize, 500, Easing.InOutSine);

                        aimWidth = counter.DrawWidth;
                    }

                    double dampRate = Math.Max(Clock.CurrentTime - lastUpdate, 0) / 1000;

                    displayFps = Interpolation.Damp(displayFps, clock.FramesPerSecond, 0.01, dampRate);
                    displayFrameTime = Interpolation.Damp(displayFrameTime, clock.ElapsedFrameTime - clock.SleptTime, 0.01, dampRate);

                    lastUpdate = clock.CurrentTime;

                    counter.Text = $"{displayFps:0}fps({displayFrameTime:0.00}ms)"
                                   + $"{(clock.MaximumUpdateHz < 10000 ? clock.MaximumUpdateHz.ToString("0") : "∞").PadLeft(4)}hz";
                }, 1000.0 / updates_per_second, true);
        }
Exemple #9
0
        protected override void LoadComplete()
        {
            base.LoadComplete();

            double lastUpdate = 0;

            thread.Scheduler.AddDelayed(() =>
            {
                if (!Counting)
                {
                    return;
                }

                double clockFps = clock.FramesPerSecond;
                double updateHz = clock.MaximumUpdateHz;

                Schedule(() =>
                {
                    if (!Precision.AlmostEquals(counter.DrawWidth, aimWidth))
                    {
                        ClearTransforms();

                        if (aimWidth == 0)
                        {
                            Size = counter.DrawSize;
                        }
                        else if (Precision.AlmostBigger(counter.DrawWidth, aimWidth))
                        {
                            this.ResizeTo(counter.DrawSize, 200, Easing.InOutSine);
                        }
                        else
                        {
                            this.Delay(1500).ResizeTo(counter.DrawSize, 500, Easing.InOutSine);
                        }

                        aimWidth = counter.DrawWidth;
                    }

                    double dampRate = Math.Max(Clock.CurrentTime - lastUpdate, 0) / 1000;

                    displayFps = Interpolation.Damp(displayFps, clockFps, 0.01, dampRate);
                    if (framesSinceLastUpdate > 0)
                    {
                        rollingElapsed = Interpolation.Damp(rollingElapsed, elapsedSinceLastUpdate / framesSinceLastUpdate, 0.01, dampRate);
                    }

                    lastUpdate = Clock.CurrentTime;

                    framesSinceLastUpdate  = 0;
                    elapsedSinceLastUpdate = 0;

                    counter.Text = $"{displayFps:0}fps({rollingElapsed:0.00}ms)"
                                   + (clock.Throttling ? $"{(updateHz < 10000 ? updateHz.ToString("0") : "∞").PadLeft(4)}hz" : string.Empty);
                });
            }, 1000.0 / updates_per_second, true);
        }
Exemple #10
0
        private void convertToStream()
        {
            if (editorBeatmap == null || changeHandler == null || beatDivisor == null)
            {
                return;
            }

            var    timingPoint   = editorBeatmap.ControlPointInfo.TimingPointAt(HitObject.StartTime);
            double streamSpacing = timingPoint.BeatLength / beatDivisor.Value;

            changeHandler.BeginChange();

            int    i    = 0;
            double time = HitObject.StartTime;

            while (!Precision.DefinitelyBigger(time, HitObject.GetEndTime(), 1))
            {
                // positionWithRepeats is a fractional number in the range of [0, HitObject.SpanCount()]
                // and indicates how many fractional spans of a slider have passed up to time.
                double positionWithRepeats = (time - HitObject.StartTime) / HitObject.Duration * HitObject.SpanCount();
                double pathPosition        = positionWithRepeats - (int)positionWithRepeats;
                // every second span is in the reverse direction - need to reverse the path position.
                if (Precision.AlmostBigger(positionWithRepeats % 2, 1))
                {
                    pathPosition = 1 - pathPosition;
                }

                Vector2 position = HitObject.Position + HitObject.Path.PositionAt(pathPosition);

                var samplePoint = (SampleControlPoint)HitObject.SampleControlPoint.DeepClone();
                samplePoint.Time = time;

                editorBeatmap.Add(new HitCircle
                {
                    StartTime          = time,
                    Position           = position,
                    NewCombo           = i == 0 && HitObject.NewCombo,
                    SampleControlPoint = samplePoint,
                    Samples            = HitObject.HeadCircle.Samples.Select(s => s.With()).ToList()
                });

                i   += 1;
                time = HitObject.StartTime + i * streamSpacing;
            }

            editorBeatmap.Remove(HitObject);

            changeHandler.EndChange();
        }
            protected override void Update()
            {
                base.Update();

                try
                {
                    var texture = Texture;

                    if (texture?.Available != true)
                    {
                        Expire();
                        return;
                    }

                    titleText.Text  = $"{texture.TextureId}. {texture.Width}x{texture.Height} ";
                    footerText.Text = Precision.AlmostBigger(usage.AverageUsagesPerFrame, 1) ? $"{usage.AverageUsagesPerFrame:N0} binds" : string.Empty;
                }
                catch { }
            }
Exemple #12
0
        private void updateStacking()
        {
            // because only blueprints of objects which are alive (via pooling) are displayed in the timeline, it's feasible to do this every-update.

            const int stack_offset = 5;

            // after the stack gets this tall, we can presume there is space underneath to draw subsequent blueprints.
            const int stack_reset_count = 3;

            Stack <HitObject> currentConcurrentObjects = new Stack <HitObject>();

            foreach (var b in SelectionBlueprints.Reverse())
            {
                // remove objects from the stack as long as their end time is in the past.
                while (currentConcurrentObjects.TryPeek(out HitObject hitObject))
                {
                    if (Precision.AlmostBigger(hitObject.GetEndTime(), b.Item.StartTime, 1))
                    {
                        break;
                    }

                    currentConcurrentObjects.Pop();
                }

                // if the stack gets too high, we should have space below it to display the next batch of objects.
                // importantly, we only do this if time has incremented, else a stack of hitobjects all at the same time value would start to overlap themselves.
                if (currentConcurrentObjects.TryPeek(out HitObject h) && !Precision.AlmostEquals(h.StartTime, b.Item.StartTime, 1))
                {
                    if (currentConcurrentObjects.Count >= stack_reset_count)
                    {
                        currentConcurrentObjects.Clear();
                    }
                }

                b.Y = -(stack_offset * currentConcurrentObjects.Count);

                currentConcurrentObjects.Push(b.Item);
            }
        }
Exemple #13
0
        private static bool FilterMuteTlo(TimelineObject tloTo, Beatmap beatmapTo, Arguments arg)
        {
            // Check whether it's defined
            if (!tloTo.CanCopy)
            {
                return(false);
            }

            // Check type
            if (!(tloTo.IsSliderEnd || tloTo.IsSpinnerEnd))
            {
                return(false);
            }

            // Check repeats
            if (tloTo.Repeat != 1)
            {
                return(false);
            }

            // Check filter snap
            // It's at least snap x or worse if the time is not a multiple of snap x / 2
            var timingPoint      = beatmapTo.BeatmapTiming.GetRedlineAtTime(tloTo.Time - 1);
            var resnappedTime    = beatmapTo.BeatmapTiming.Resnap(tloTo.Time, arg.Snap1, arg.Snap2, false, timingPoint);
            var beatsFromRedline = (resnappedTime - timingPoint.Offset) / timingPoint.MpB;
            var dist1            = beatsFromRedline * arg.Snap1 / (arg.Snap1 == 1 ? 4 : 2);
            var dist2            = beatsFromRedline * arg.Snap2 / (arg.Snap2 == 1 ? 4 : arg.Snap2 == 3 ? 3 : 2);

            dist1 %= 1;
            dist2 %= 1;
            if (Precision.AlmostEquals(dist1, 0) || Precision.AlmostEquals(dist1, 1) ||
                Precision.AlmostEquals(dist2, 0) || Precision.AlmostEquals(dist2, 1))
            {
                return(false);
            }

            // Check filter temporal length
            return(Precision.AlmostBigger(tloTo.Origin.TemporalLength, arg.MinLength * timingPoint.MpB));
        }
Exemple #14
0
 private static bool almostBigger(double value1, double value2)
 {
     return(Precision.AlmostBigger(value1, value2, timing_precision));
 }
Exemple #15
0
 public bool IsScrolledToEnd(float lenience = Precision.FLOAT_EPSILON) => Precision.AlmostBigger(target, scrollableExtent, lenience);
        public void TestSubMenuOverflow(Anchor anchor, Direction direction)
        {
            createMenu(direction);
            AddStep($"anchor menu {anchor}", () =>
            {
                var menu    = Menus.GetSubMenu(0);
                menu.Anchor = menu.Origin = anchor;
            });

            AddStep("Click item", () => ClickItem(0, 1));
            menuOpenAndVisible(1);

            AddStep("Click item", () => ClickItem(1, 0));
            menuOpenAndVisible(2);

            AddStep("Click item", () => ClickItem(2, 0));
            menuOpenAndVisible(3);

            AddStep("Click item", () => ClickItem(3, 0));
            menuOpenAndVisible(4);

            void menuOpenAndVisible(int index) => AddAssert("Menu is open and visible", () =>
            {
                var menu = Menus.GetSubMenu(index);
                return(menu.State == MenuState.Open && menu.ScreenSpaceDrawQuad.GetVertices().ToArray().All(v => Precision.AlmostBigger(ScreenSpaceDrawQuad.BottomRight.X, v.X, 1) && Precision.AlmostBigger(ScreenSpaceDrawQuad.BottomRight.Y, v.Y, 1)));
            });
        }