public LongVisualNote([NotNull] VisualBeatmap beatmap, [NotNull] LongNote baseNote, [NotNull] StageMetrics metrics) : base(beatmap, baseNote) { _baseNote = baseNote; _metrics = metrics; _noteRectangle = new TexturedRectangle(beatmap.GraphicsDevice); PreviewStartY = beatmap.CalculateY(baseNote.StartTick, metrics, metrics.FinishLineY); PreviewEndY = beatmap.CalculateY(baseNote.EndTick, metrics, metrics.FinishLineY); }
public FloorVisualNote([NotNull] VisualBeatmap beatmap, [NotNull] FloorNote baseNote, [NotNull] StageMetrics metrics) : base(beatmap, baseNote) { _baseNote = baseNote; _metrics = metrics; _noteRectangle = new TexturedRectangle(beatmap.GraphicsDevice); _linkHexahedron = new ColoredHexahedron(beatmap.GraphicsDevice); PreviewY = beatmap.CalculateY(baseNote.Tick, metrics, metrics.FinishLineY); }
public SkyVisualNote([NotNull] VisualBeatmap beatmap, [NotNull] SkyNote baseNote, [NotNull] ArcVisualNote parent, [NotNull] StageMetrics metrics) : base(beatmap, baseNote) { _metrics = metrics; Parent = parent; PreviewY = beatmap.CalculateY(baseNote.Tick, metrics, metrics.FinishLineY); var graphicsDevice = beatmap.GraphicsDevice; _graphicsDevice = graphicsDevice; _vertexBuffer1 = new VertexBuffer(graphicsDevice, VertexPositionColorTexture.VertexDeclaration, 16, BufferUsage.WriteOnly); _indexBuffer1 = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, 24, BufferUsage.WriteOnly); _vertexBuffer2 = new VertexBuffer(graphicsDevice, VertexPositionColorTexture.VertexDeclaration, 8, BufferUsage.WriteOnly); _indexBuffer2 = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, 12, BufferUsage.WriteOnly); var indices1 = new ushort[] { // bottom, top 0, 1, 2, 2, 1, 3, 4, 5, 6, 6, 5, 7, // front, back 8, 9, 10, 10, 9, 11, 12, 13, 14, 14, 13, 15 }; _indexBuffer1.SetData(indices1); var indices2 = new ushort[] { 0, 1, 2, 2, 1, 3, 4, 5, 6, 6, 5, 7, }; _indexBuffer2.SetData(indices2); _shadowRectangle = new ColoredRectangle(graphicsDevice); }
public ArcVisualNote([NotNull] VisualBeatmap beatmap, [NotNull] ArcNote baseNote, [NotNull] StageMetrics metrics) : base(beatmap, baseNote) { _baseNote = baseNote; _metrics = metrics; PreviewStartY = beatmap.CalculateY(baseNote.StartTick, metrics, metrics.FinishLineY); PreviewEndY = beatmap.CalculateY(baseNote.EndTick, metrics, metrics.FinishLineY); _arcMesh = new BottomlessColoredTriangularPrism(beatmap.GraphicsDevice); _shadow = new ColoredParallelogram(beatmap.GraphicsDevice); _support = new TexturedRectangle(beatmap.GraphicsDevice); _header = new BottomlessColoredTetrahedron(beatmap.GraphicsDevice); if (baseNote.SkyNotes != null && baseNote.SkyNotes.Length > 0) { SkyVisualNotes = baseNote.SkyNotes.Select(n => new SkyVisualNote(beatmap, n, this, metrics)).ToArray(); } }
/// <summary> /// Calculate a beatmap time's Y distance according to timing and metrics. /// </summary> /// <param name="beatmapTicks">Current beatmap time, in milliseconds. Please note that beatmap time does not equal to audio time when a beatmap's audio offset is non-zero.</param> /// <param name="metrics">Stage metrics.</param> /// <param name="addition">The final addition value. This value is directly added to the calculated value. Example usage: assign this parameter the finishing line's Y distance.</param> /// <returns></returns> public float CalculateY(int beatmapTicks, [NotNull] StageMetrics metrics, float addition) { const float timeScale = 0.6f; var timingNotes = Timings; if (timingNotes.Length == 0) { return(0); } var measureLength = metrics.FloorNoteHeight * 6; var result = 0f; for (var i = 0; i < timingNotes.Length; ++i) { var timingNote = timingNotes[i]; if (beatmapTicks < timingNote.Tick) { break; } if (i >= timingNotes.Length - 1 || beatmapTicks < timingNotes[i + 1].Tick) { result += (beatmapTicks - timingNote.Tick) * timingNote.Bpm; } else { result += (timingNotes[i + 1].Tick - timingNote.Tick) * timingNote.Bpm; } } result /= 100_000f; result *= measureLength * timeScale * metrics.Speed; result += addition; return(result); }
/// <summary> /// Creates a new <see cref="VisualBeatmap"/> instance from a <see cref="Beatmap"/> using specified stage metrics. /// </summary> /// <param name="graphicsDevice">A <see cref="Microsoft.Xna.Framework.Graphics.GraphicsDevice"/> used to draw the beatmap's notes.</param> /// <param name="baseBeatmap"></param> /// <param name="metrics">Stage metrics.</param> public VisualBeatmap([NotNull] GraphicsDevice graphicsDevice, [NotNull] Beatmap baseBeatmap, [NotNull] StageMetrics metrics) { GraphicsDevice = graphicsDevice; BaseBeatmap = baseBeatmap; Timings = baseBeatmap.Notes.Where(n => n.Type == NoteType.Timing).Cast <TimingNote>().ToArray(); var visualNotes = baseBeatmap.Notes.Where(n => n.Type != NoteType.Timing).Select <NoteBase, VisualNoteBase>(n => { switch (n.Type) { case NoteType.Floor: return(new FloorVisualNote(this, (FloorNote)n, metrics)); case NoteType.Long: return(new LongVisualNote(this, (LongNote)n, metrics)); case NoteType.Arc: return(new ArcVisualNote(this, (ArcNote)n, metrics)); default: throw new ArgumentOutOfRangeException(); } }).ToArray(); VisualNotes = visualNotes; // Scan sync sky notes and add lines between the floor note and sky note. // Credits: @money, @RW, @JDF, @L-F0rce var allArcVisualNotes = visualNotes.Where(note => note.Type == NoteType.Arc).Cast <ArcVisualNote>().ToArray(); for (var i = 0; i < visualNotes.Length; ++i) { var visualNote = visualNotes[i]; if (visualNote.Type != NoteType.Floor || i >= visualNotes.Length - 1) { continue; } var n = (FloorVisualNote)visualNote; var floorBase = (FloorNote)n.BaseNote; // TODO: Naive method. Should be optimized. foreach (var arcVisualNote in allArcVisualNotes) { if (arcVisualNote.SkyVisualNotes == null || arcVisualNote.SkyVisualNotes.Length == 0) { continue; } foreach (var skyVisualNote in arcVisualNote.SkyVisualNotes) { if (Math.Abs(((SkyNote)skyVisualNote.BaseNote).Tick - floorBase.Tick) <= 1) { n.SynchronizedSkyVisualNote = skyVisualNote; break; } } if (n.SynchronizedSkyVisualNote != null) { break; } } } // "Supports" foreach (var arcVisualNote in allArcVisualNotes) { var n = (ArcNote)arcVisualNote.BaseNote; var ancestor = allArcVisualNotes.FirstOrDefault(note => { var anotherArcNote = (ArcNote)note.BaseNote; return(anotherArcNote.EndTick == n.StartTick && anotherArcNote.IsPlayable && anotherArcNote.Color == n.Color); }); if (ancestor == null) { arcVisualNote.ShouldDrawSupport = true; arcVisualNote.ShouldDrawHeader = true; continue; } if (!((ArcNote)ancestor.BaseNote).StartY.Equals(((ArcNote)ancestor.BaseNote).EndY)) { arcVisualNote.ShouldDrawSupport = true; } } }