// For ScoreEditor public void Render(Graphics context, Score score, ScoreEditorConfig config, ScoreEditorLook look, float scrollOffsetY, Rectangle selectionRectangle) { var hasAnyBar = score?.HasAnyBar ?? false; if (hasAnyBar) { RenderBars(context, score, config, look, scrollOffsetY); } var hasAnyNote = score?.HasAnyNote ?? false; if (hasAnyNote) { RenderNotes(context, score, config, look, scrollOffsetY); } RenderSelectionRectangle(context, selectionRectangle); }
// For ScorePreviewer public void Render(Graphics context, Score score, ScoreEditorConfig config, ScoreEditorLook look, float scrollOffsetY, TimeSpan now) { var hasAnyBar = score?.HasAnyBar ?? false; if (hasAnyBar) { RenderBars(context, score, config, look, scrollOffsetY); } var hasAnyNote = score?.HasAnyNote ?? false; if (hasAnyNote) { RenderNotes(context, score, config, look, scrollOffsetY); } if (look.TimeInfoVisible) { var controlArea = new Rectangle(Point.Zero, context.Bounds.Size); DrawBarTimePreviewInfo(context, controlArea, now); } }
public static float GetScrollOffsetY(Score score, IReadOnlyList <IReadOnlyList <TimeSpan> > scoreTimingInfo, TimeSpan now, ScoreEditorLook look, Size clientSize, float fullHeight) { if (!score.HasAnyBar) { return(0); } var middleY = clientSize.Height / 2; var unit = look.BarLineSpaceUnit; // If we haven't reached the first note... var firstBarTimingInfo = scoreTimingInfo[0]; if (now < firstBarTimingInfo[0]) { var firstDeltaTime = firstBarTimingInfo[1] - firstBarTimingInfo[0]; var expectedUnits = unit * (float)(firstBarTimingInfo[0].TotalSeconds / firstDeltaTime.TotalSeconds); var firstRatio = (float)((now - firstBarTimingInfo[0]).TotalSeconds / scoreTimingInfo[0][0].TotalSeconds); return(middleY + expectedUnits * firstRatio); } // Or the song has ended... var lastBarInfo = scoreTimingInfo[scoreTimingInfo.Count - 1]; if (now > lastBarInfo[lastBarInfo.Count - 1]) { var lastDeltaTime = lastBarInfo[lastBarInfo.Count - 1] - lastBarInfo[lastBarInfo.Count - 2]; var expectedUnits = unit * (float)((now - lastBarInfo[lastBarInfo.Count - 1]).TotalSeconds / lastDeltaTime.TotalSeconds); return(middleY + fullHeight + expectedUnits); } // Otherwise, scan through the bars and find the first match. var currentBar = score.Bars[0]; for (var i = 1; i < score.Bars.Count; ++i) { if (scoreTimingInfo[i][0] >= now) { break; } currentBar = score.Bars[i]; } // Find the grid. var currentBarIndex = currentBar.Basic.Index; var currentBarTimingInfo = scoreTimingInfo[currentBarIndex]; var prevTimingIndex = 0; for (var i = 1; i < currentBarTimingInfo.Count; ++i) { if (currentBarTimingInfo[i] > now) { break; } prevTimingIndex = i; } TimeSpan nextTiming; var prevTiming = currentBarTimingInfo[prevTimingIndex]; if (prevTimingIndex == currentBarTimingInfo.Count - 1) { // The "last line of last bar" occasion is already filtered out, // so here we handle a simpler case. nextTiming = scoreTimingInfo[currentBarIndex + 1][0]; } else { nextTiming = currentBarTimingInfo[prevTimingIndex + 1]; } var ratio = (float)((now - prevTiming).TotalSeconds / (nextTiming - prevTiming).TotalSeconds); float offset = middleY; for (var i = 0; i < currentBarIndex; ++i) { offset += unit * score.Bars[i].GetNumberOfGrids(); } offset += unit * prevTimingIndex + unit * ratio; return(offset); }
private void RenderBars(Graphics context, Score score, ScoreEditorConfig config, ScoreEditorLook look, float barStartY) { var bars = score.Bars; var primaryBeatMode = look.PrimaryBeatMode; var gridArea = ScoreEditorLayout.GetGridArea(config, context.Bounds); var barArea = ScoreEditorLayout.GetBarArea(config, context.Bounds); var infoArea = ScoreEditorLayout.GetInfoArea(config, context.Bounds); var unit = look.BarLineSpaceUnit; var noteRadius = config.NoteRadius; foreach (var bar in bars) { var numberOfGrids = bar.GetNumberOfGrids(); var visible = ScoreEditorLayout.IsBarVisible(barArea, barStartY, numberOfGrids, unit); if (visible) { if (look.BarInfoTextVisible) { DrawBarInfoText(context, bar, infoArea, barStartY); } DrawBarGrid(context, gridArea, config, barStartY, numberOfGrids, unit, noteRadius, primaryBeatMode); DrawBarOutline(context, bar, barArea, barStartY, numberOfGrids, unit); } barStartY -= numberOfGrids * unit; } }
private void DrawNotes(Graphics context, Score score, Rectangle gridArea, ScoreEditorConfig config, ScoreEditorLook look, Rectangle specialNoteArea, float noteStartY, float radius) { if (!score.HasAnyNote) { return; } var unit = look.BarLineSpaceUnit; var startPositionFont = _noteStartPositionFont; var shouldDrawIndicators = look.IndicatorsVisible; var numColumns = config.NumberOfColumns; foreach (var bar in score.Bars) { var numberOfGrids = bar.GetNumberOfGrids(); if (bar.Helper.HasAnyNote) { foreach (var note in bar.Notes) { if (!ScoreEditorLayout.IsNoteVisible(note, gridArea, noteStartY, unit, radius)) { continue; } if (note.Helper.IsGaming) { var x = ScoreEditorLayout.GetNotePositionX(note, gridArea, numColumns); var y = ScoreEditorLayout.GetNotePositionY(note, unit, noteStartY); var h = note.Helper; if (h.IsSlide) { if (h.HasNextFlick) { DrawFlickNote(context, note, x, y, radius, note.Basic.FlickType); } else { DrawSlideNote(context, note, x, y, radius, h.IsSlideMidway); } } else if (h.IsHoldStart) { DrawHoldNote(context, note, x, y, radius); } else { if (note.Basic.FlickType != NoteFlickType.None) { DrawFlickNote(context, note, x, y, radius, note.Basic.FlickType); } else if (h.IsHoldEnd) { DrawHoldNote(context, note, x, y, radius); } else { DrawTapNote(context, note, x, y, radius); } } // Indicators if (shouldDrawIndicators) { if (note.Helper.IsSync) { context.FillCircle(_syncIndicatorBrush, x + radius, y - radius, Definitions.IndicatorRadius); } if (note.Helper.IsHold) { context.FillCircle(_holdIndicatorBrush, x - radius, y + radius, Definitions.IndicatorRadius); } if (note.Helper.IsSlide) { context.FillCircle(_slideIndicatorBrush, x + radius, y + radius, Definitions.IndicatorRadius); } else if (note.Helper.IsFlick) { context.FillCircle(_flickIndicatorBrush, x + radius, y + radius, Definitions.IndicatorRadius); } } // Start position if (note.Basic.StartPosition != note.Basic.FinishPosition) { var startPositionX = x - radius - Definitions.StartPositionFontSize / 2; var startPositionY = y - radius - Definitions.StartPositionFontSize / 2; var text = ((int)note.Basic.StartPosition).ToString(); var textSize = context.MeasureString(startPositionFont, text); context.FillString(_noteCommonFill, startPositionFont, text, startPositionX, startPositionY + textSize.Y); } } else if (note.Helper.IsSpecial) { // Draw a special note (a rectangle) var left = specialNoteArea.Left + radius * 4; var gridY = ScoreEditorLayout.GetNotePositionY(note, unit, noteStartY); var top = gridY - radius * Definitions.SpecialNoteHeightFactor; var width = specialNoteArea.Right - left; var height = radius * 2 * Definitions.SpecialNoteHeightFactor; context.DrawRectangle(_specialNoteStroke, left, top, width, height); context.FillRectangle(_specialNoteFill, left, top, width, height); string specialNoteText; switch (note.Basic.Type) { case NoteType.VariantBpm: specialNoteText = $"BPM: {note.Params.NewBpm:0.00}"; break; default: throw new ArgumentOutOfRangeException(nameof(note.Basic.Type), note.Basic.Type, null); } var rect = context.MeasureString(_specialNoteDescriptionFont, specialNoteText); var textLeft = left + 2; var textTop = gridY + rect.Y / 2; context.FillString(_specialNoteTextBrush, _specialNoteDescriptionFont, specialNoteText, textLeft, textTop); } } } noteStartY -= numberOfGrids * unit; } }
private void DrawNoteConnections(Graphics context, Score score, Rectangle gridArea, ScoreEditorConfig config, ScoreEditorLook look, float scrollOffsetY, float noteStartY, float radius) { if (!score.HasAnyNote) { return; } var unit = look.BarLineSpaceUnit; var numColumns = config.NumberOfColumns; foreach (var bar in score.Bars) { var numberOfGrids = bar.GetNumberOfGrids(); if (bar.Helper.HasAnyNote) { foreach (var note in bar.Notes) { var thisStatus = ScoreEditorLayout.GetNoteOnStageStatus(note, gridArea, noteStartY, unit, radius); var x1 = ScoreEditorLayout.GetNotePositionX(note, gridArea, numColumns); var y1 = ScoreEditorLayout.GetNotePositionY(note, unit, noteStartY); if (note.Helper.HasNextSync && thisStatus == OnStageStatus.OnStage) { var n2 = note.Editor.NextSync; var x2 = ScoreEditorLayout.GetNotePositionX(n2, gridArea, numColumns); // Draw sync line context.DrawLine(_syncLineStroke, x1, y1, x2, y1); } if (note.Helper.IsHoldStart) { var n2 = note.Editor.HoldPair; var s2 = noteStartY; // We promise only calculate the latter note, so this method works. if (note.Basic.Bar != n2.Basic.Bar) { for (var i = note.Basic.Bar.Basic.Index; i < n2.Basic.Bar.Basic.Index; ++i) { s2 -= score.Bars[i].GetNumberOfGrids() * unit; } } var thatStatus = ScoreEditorLayout.GetNoteOnStageStatus(n2, gridArea, s2, unit, radius); if ((int)thisStatus * (int)thatStatus <= 0) { var x2 = ScoreEditorLayout.GetNotePositionX(n2, gridArea, numColumns); var y2 = ScoreEditorLayout.GetNotePositionY(score.Bars, n2.Basic.Bar.Basic.Index, n2.Basic.IndexInGrid, unit, scrollOffsetY); // Draw hold line context.DrawLine(_holdLineStroke, x1, y1, x2, y2); } } if (note.Helper.HasNextFlick) { var n2 = note.Editor.NextFlick; var s2 = noteStartY; if (note.Basic.Bar != n2.Basic.Bar) { for (var i = note.Basic.Bar.Basic.Index; i < n2.Basic.Bar.Basic.Index; ++i) { s2 -= score.Bars[i].GetNumberOfGrids() * unit; } } var thatStatus = ScoreEditorLayout.GetNoteOnStageStatus(n2, gridArea, s2, unit, radius); if ((int)thisStatus * (int)thatStatus <= 0) { var x2 = ScoreEditorLayout.GetNotePositionX(n2, gridArea, numColumns); var y2 = ScoreEditorLayout.GetNotePositionY(score.Bars, n2.Basic.Bar.Basic.Index, n2.Basic.IndexInGrid, unit, scrollOffsetY); // Draw flick line context.DrawLine(_flickLineStroke, x1, y1, x2, y2); } } if (note.Helper.HasNextSlide) { var n2 = note.Editor.NextSlide; var s2 = noteStartY; if (note.Basic.Bar != n2.Basic.Bar) { for (var i = note.Basic.Bar.Basic.Index; i < n2.Basic.Bar.Basic.Index; ++i) { s2 -= score.Bars[i].GetNumberOfGrids() * unit; } } var thatStatus = ScoreEditorLayout.GetNoteOnStageStatus(n2, gridArea, s2, unit, radius); if ((int)thisStatus * (int)thatStatus <= 0) { var x2 = ScoreEditorLayout.GetNotePositionX(n2, gridArea, numColumns); var y2 = ScoreEditorLayout.GetNotePositionY(score.Bars, n2.Basic.Bar.Basic.Index, n2.Basic.IndexInGrid, unit, scrollOffsetY); // Draw slide line context.DrawLine(_slideLineStroke, x1, y1, x2, y2); } } } } noteStartY -= numberOfGrids * unit; } }
private void RenderNotes(Graphics context, Score score, ScoreEditorConfig config, ScoreEditorLook look, float scrollOffsetY) { var gridArea = ScoreEditorLayout.GetGridArea(config, context.Bounds); var radius = config.NoteRadius; var specialNoteArea = ScoreEditorLayout.GetSpecialNoteArea(config, context.Bounds); DrawNoteConnections(context, score, gridArea, config, look, scrollOffsetY, scrollOffsetY, radius); DrawNotes(context, score, gridArea, config, look, specialNoteArea, scrollOffsetY, radius); }