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(); } }
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); }
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"); }
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; }
/// <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); }
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); }
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 { } }
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); } }
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)); }
private static bool almostBigger(double value1, double value2) { return(Precision.AlmostBigger(value1, value2, timing_precision)); }
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))); }); }