public override void drawGeoChunk(Geo geo) { LineGeo lineGeo = (LineGeo)geo; foreach (var vb in lineGeo.lineVb) { GraphicsDevice.SetVertexBuffer(vb); GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 3, vb.VertexCount - 5); } foreach (var vb in lineGeo.hLineVb) { GraphicsDevice.SetVertexBuffer(vb); GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, vb.VertexCount); } }
void createLineSegment(ref int numVerts, ref int numHLineVerts, LineGeo geo, float lineWidth) { //Console.WriteLine(numVerts); if (lineWidth > 0) { if (numVerts > 5 || numHLineVerts > 1) { if (numHLineVerts > 1) { VertexBuffer vb = new VertexBuffer(GraphicsDevice, lineVertDecl, numHLineVerts, BufferUsage.WriteOnly); vb.SetData(hLineVerts, 0, numHLineVerts); geo.hLineVb.Add(vb); numHLineVerts = 0; } if (numVerts > 5) { VertexBuffer vb = new VertexBuffer(GraphicsDevice, lineVertDecl, numVerts, BufferUsage.WriteOnly); vb.SetData(lineVerts, 0, numVerts); geo.lineVb.Add(vb); numVerts = 3; } } } }
//static string GetName<T>(T item) where T : class //{ // return typeof(T).GetProperties()[0].Name; //} public override void createGeoChunk(out Geo geo, BoundingBox bbox, Midi.Track midiTrack, TrackProps trackProps, MaterialProps texMaterial) { LineGeo lineGeo = new LineGeo(); geo = lineGeo; if (LineWidth == 0) { return; } List <Midi.Note> noteList = midiTrack.Notes; //List<Midi.Note> noteList = getNotes(0, midiTrack, songDrawProps); if (noteList.Count == 0) { return; } int vertIndex = 3; int hLineVertIndex = 0; int completeNoteListIndex = midiTrack.Notes.IndexOf(noteList[0]); float vpLineWidth = VpLineWidth; float maxNumBboxesPerScreenWidth = 1000; float bboxMinSqLength = (float)Math.Pow(Project.Props.Camera.ViewportSize.X / maxNumBboxesPerScreenWidth, 2); //for (int i = 0; i < 100; i++) //{ // vertIndex = 30000; // createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth); //} //return; for (int n = 0; n < noteList.Count; n++) { //Get current note Midi.Note note = noteList[n], nextNote; if (note.start > Project.Notes.SongLengthT) //only if audio ends before the notes end { continue; } if (n < noteList.Count - 1) { nextNote = noteList[n + 1]; } else if (completeNoteListIndex < midiTrack.Notes.Count - 1) { nextNote = midiTrack.Notes[completeNoteListIndex + 1]; } else { nextNote = note; } Vector2 noteStart = Project.getScreenPos(note.start, note.pitch); float noteEnd = Project.getScreenPos(note.stop, note.pitch).X; Vector2 nextNoteStart = Project.getScreenPos(nextNote.start, nextNote.pitch); if (noteEnd > nextNoteStart.X && completeNoteListIndex < midiTrack.Notes.Count - 1) { noteEnd = nextNoteStart.X; } bool endOfSegment = false; if ((float)(nextNote.start - note.stop) > Qn_gapThreshold * Project.Notes.TicksPerBeat || note == nextNote) { if (nextNoteStart.X != noteStart.X) { nextNoteStart.Y = (int)MathHelper.Lerp(noteStart.Y, nextNoteStart.Y, (float)(noteEnd - noteStart.X) / (nextNoteStart.X - noteStart.X)); } nextNoteStart.X = noteEnd; endOfSegment = true; } float startDraw = noteStart.X; float endDraw = nextNoteStart.X; //Don't draw if length is 0 if (startDraw == endDraw) { continue; } float curvature = calcLinearLineAngle(n, trackProps.TrackView.Curve); //if (n > 0) //{ // float prevCurvature = calcLinearLineAngle(n - 1, trackProps.TrackView.Curve); // if (prevCurvature > curvature) // curvature = (prevCurvature + curvature) / 2; //Prevent too big jumps between levels of tesselation which will cause sharp bends //} if (n < noteList.Count - 1) { curvature = Math.Max(curvature, calcLinearLineAngle(n + 1, trackProps.TrackView.Curve)); } //curvature /= (float)Math.PI; //Map to [0,1] curvature = Math.Min(curvature, 0.97f * (float)Math.PI); //Clip below 180 degrees to avoid extreme tesselation curvature = (float)Math.Pow(curvature, 2.25) * 1000; float step; if (curvature == 0) { step = (endDraw - startDraw) * 0.999f; //Only one point for the note } else { step = 1 / curvature; } if (step >= endDraw - startDraw) { step = (endDraw - startDraw);// * 0.999f; } int iterations = (int)((endDraw - startDraw) / step); if (iterations < 0) { throw new OverflowException($"Too many vertices for note {n}, track {trackProps.TrackView.TrackNumber}."); } step = (endDraw - startDraw) / (iterations + 1); Vector3 bboxStart = Vector3.Zero; for (float x = startDraw; x <= endDraw + 0.00001f; x += step) { Vector3 center, normal, vertexOffset; getCurvePoint(out center, out normal, out vertexOffset, step, x, trackProps, vpLineWidth); //normal.X = curvature/10f; lineVerts[vertIndex].normal = lineVerts[vertIndex + 1].normal = normal; //Create vertices //adjustCurvePoint(center, vertexOffset, -1, trackProps, lineVerts, vertIndex, step, vpLineWidth); //adjustCurvePoint(center, vertexOffset, 1, trackProps, lineVerts, vertIndex + 1, step, vpLineWidth); //curvature = trackProps.TrackView.Curve.EvaluateCurvature(Project.getTimeT(x)); //center.Y = curvature / 10; lineVerts[vertIndex].pos = center - vertexOffset; lineVerts[vertIndex + 1].pos = center + vertexOffset; lineVerts[vertIndex].center = lineVerts[vertIndex + 1].center = center; float normStepFromNoteStart = (x - startDraw) / (nextNoteStart.X - noteStart.X); //lineVerts[vertIndex].normStepFromNoteStart = lineVerts[vertIndex + 1].normStepFromNoteStart = normStepFromNoteStart; lineVerts[vertIndex].normPos = new Vector2(normStepFromNoteStart, 0); lineVerts[vertIndex + 1].normPos = new Vector2(normStepFromNoteStart, 1); if (texMaterial.TexProps.Texture != null) { calcTexCoords(out lineVerts[vertIndex].texCoords, out lineVerts[vertIndex + 1].texCoords, texMaterial.TexProps, x - startDraw, normStepFromNoteStart, vpLineWidth, lineVerts[vertIndex].pos, lineVerts[vertIndex + 1].pos); } if (LineType == VisualMusic.LineType.Ribbon) { float hLineStart = center.X; float hLineEnd = hLineStart; do { hLineEnd += step; } while ((int)center.Y == (int)Project.getCurveScreenY((float)hLineEnd + step, trackProps.TrackView.Curve) && hLineEnd < endDraw); if (hLineEnd > hLineStart + vpLineWidth / 2) { hLineVerts[hLineVertIndex++] = lineVerts[vertIndex]; hLineVerts[hLineVertIndex++] = lineVerts[vertIndex + 1]; } //float horizontalFactor = Math.Abs(normal.Y); //float horizontalLimit = 0.98f; //float minThickness = 0.001f; //if (horizontalFactor > horizontalLimit) //{ //todo use vertexoffset for non-ribbon instead of normal // horizontalFactor = (horizontalFactor - horizontalLimit) / (1 - horizontalLimit); //[horizontalFactor, 1] -> [0, 1] // lineVerts[vertIndex].pos.Y -= minThickness * horizontalFactor * Math.Sign(normal.X); //} } if (x == startDraw && vertIndex > 3) { lineVerts[vertIndex].pos = lineVerts[vertIndex - 2].pos; lineVerts[vertIndex + 1].pos = lineVerts[vertIndex - 1].pos; } //Create bounding box if (bboxStart == Vector3.Zero) { bboxStart = lineVerts[vertIndex].center; } Vector3 bboxEnd = lineVerts[vertIndex].center; if (Vector3.DistanceSquared(bboxStart, bboxEnd) > bboxMinSqLength) { Vector3 bboxCenter = (bboxStart + bboxEnd) / 2; geo.bboxes.Add(new BoundingBoxEx(bboxCenter, bboxEnd - bboxCenter, bboxEnd - lineVerts[vertIndex].pos, new Vector3(0, 0, 0))); bboxStart = bboxEnd; } vertIndex += 2; if (vertIndex >= MaxLineVerts - 2 || hLineVertIndex >= MaxHLineVerts - 2) { createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth); x -= step; } //break; } if (!(bool)Continuous) { endOfSegment = true; //One draw call per note. Can be used to avoid glitches between notes because of instant IN.normStepFromNoteStart interpolation from 1 to 0. } if (endOfSegment) { createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth); } completeNoteListIndex++; } createLineSegment(ref vertIndex, ref hLineVertIndex, lineGeo, vpLineWidth); }