public static SelectedNoteArea SelectedNoteArea(this NoteBase note, Point p, IReadOnlyEditorLaneEnvironment env) { var cr = note.NoteSize.Size - 2; var areaRatio = (lr : 1, cr : cr <= 0 ? 0 : cr, rr : 1); var rect = note.GetRectangle(env); // 実装微妙かも Func <SelectedNoteArea> fun = () => { var areaSum = areaRatio.lr + areaRatio.cr + areaRatio.rr; if (p.X < rect.X + rect.Width * areaRatio.lr / areaSum) { return(UI.SelectedNoteArea.Left); } if (p.X < rect.X + rect.Width * (areaRatio.lr + areaRatio.cr) / areaSum) { return(UI.SelectedNoteArea.Center); } return(UI.SelectedNoteArea.Right); }; if (rect.Contains(p)) { return(fun()); } rect.X -= (int)(env.LaneUnitWidth * MadcaEnv.LaneCount); if (rect.Contains(p)) { return(fun()); } return(UI.SelectedNoteArea.None); }
public static void DrawToLane(System.Drawing.Graphics g, IReadOnlyEditorLaneEnvironment env, NoteBase note) { // NOTE: お試し実装 using (var sb = new SolidBrush(NoteGraphicsGenerator.GetColor(note.NoteType))) using (var pen = new Pen(Color.White)) { g.Clip = new Region(env.LaneRect); var rect = note.GetRectangle(env); if (note.NoteType == NoteType.HoldRelay) { g.DrawRectangle(pen, rect); } else { g.FillRectangle(sb, rect); } DrawToLanePreviewNoteFrame(g, rect, note as PreviewNote); // 水平位置を1周分ずらしてもう一回描画 rect.X -= (int)(MadcaEnv.LaneCount * env.LaneUnitWidth); if (note.NoteType == NoteType.HoldRelay) { g.DrawRectangle(pen, rect); } else { g.FillRectangle(sb, rect); } DrawToLanePreviewNoteFrame(g, rect, note as PreviewNote); g.ResetClip(); } }
public static GraphicsPath GetGraphicsPath(this Hold hold, IReadOnlyEditorLaneEnvironment env) { var ps1 = new List <Point>(); var ps2 = new List <Point>(); var beginRect = hold.HoldBegin.GetRectangle(env); ps1.Add(beginRect.GetLeftMiddle()); ps2.Add(beginRect.GetRightMiddle()); foreach (var note in hold.AllNotes.Where(x => x != hold.HoldBegin).OrderBy(x => x.Timing)) { var rect = note.GetRectangle(env); var diff = note.Lane.RawLane - hold.HoldBegin.Lane.RawLane; rect.X = beginRect.X + diff * (int)env.LaneUnitWidth; ps1.Add(rect.GetLeftMiddle()); ps2.Add(rect.GetRightMiddle()); } ps2.Reverse(); ps1.AddRange(ps2); var gPath = new GraphicsPath(); for (int i = 0; i < ps1.Count - 1; ++i) { gPath.AddLine(ps1[i], ps1[i + 1]); } return(gPath); }
public Rectangle GetRectangle(IReadOnlyEditorLaneEnvironment env) { var loc = PositionConverter.ConvertVirtualToRealNorm(env, new Position(Lane, Timing)); int width = NoteEnvironment.NoteWidth(NoteSize.Size, env); int height = NoteEnvironment.NoteHeight; return(new Rectangle(loc.X, loc.Y - NoteEnvironment.NoteHeight / 2, width, height)); }
/// <summary> /// 仮想座標から絶対実座標を計算します /// x座標のRangeは(-inf, inf) /// </summary> /// <param name="env">エディタレーン環境</param> /// <param name="position">仮想座標</param> /// <returns></returns> public static Point ConvertVirtualToReal(IReadOnlyEditorLaneEnvironment env, Position position) { var px = (int)(env.SideMargin + position.Lane.RawLane * env.LaneUnitWidth - env.OffsetXRaw); var py = (int)(position.Timing.BarRatio * env.TimingUnitHeight - env.OffsetY); px += env.PanelRegion.X; py = env.PanelRegion.Height - py - env.PanelRegion.Y - (int)env.BottomMargin; return(new Point(px, py)); }
/// <summary> /// X方向で端がつながっているレーン上で見たときに,矩形領域内に座標が含まれているかを判定します /// </summary> /// <param name="rect"></param> /// <param name="p"></param> /// <param name="env"></param> /// <returns></returns> public static bool ContainsEx(this Rectangle rect, Point p, IReadOnlyEditorLaneEnvironment env) { var tmp = rect; if (tmp.Contains(p)) { return(true); } tmp.X -= (int)(env.LaneUnitWidth * MadcaEnv.LaneCount); return(tmp.Contains(p)); }
public static void DrawToLane(System.Drawing.Graphics g, IReadOnlyEditorLaneEnvironment env, NoteBook noteBook) { // HACK: 描画対象にするHoldを画面内にあるもののみに絞ったほうがいいんじゃない? foreach (var hold in noteBook.Holds) { DrawHoldRegionToLane(g, env, hold); foreach (var note in hold.AllNotes) { DrawToLane(g, env, note); } } foreach (var note in noteBook.Notes) { DrawToLane(g, env, note); } }
public static void DrawHoldRegionToLane(System.Drawing.Graphics g, IReadOnlyEditorLaneEnvironment env, Hold hold) { using (var sb = new SolidBrush(Color.FromArgb(200, 200, 175, 90))) using (var path = hold.GetGraphicsPath(env)) using (var matToLeft = new Matrix()) using (var matToRight = new Matrix()) using (var matToReset = new Matrix()) { var laneWidth = env.LaneUnitWidth * MadcaEnv.LaneCount; g.Clip = new Region(env.LaneRect); matToLeft.Translate(-laneWidth, 0); matToRight.Translate(laneWidth, 0); var leftTimes = 0; try { g.FillPath(sb, path); } catch (Exception) { } while (path.GetBounds().Right > env.LaneRect.Right) { path.Transform(matToLeft); try { g.FillPath(sb, path); } catch (Exception) { } leftTimes++; } matToReset.Translate(laneWidth * leftTimes, 0); path.Transform(matToReset); while (path.GetBounds().Left < env.LaneRect.Left) { path.Transform(matToRight); try { g.FillPath(sb, path); } catch (Exception) { } } g.ResetClip(); } }
public static bool Contains(this Hold hold, Point p, IReadOnlyEditorLaneEnvironment env) { var laneWidth = env.LaneUnitWidth * MadcaEnv.LaneCount; var matToLeft = new Matrix(); matToLeft.Translate(-laneWidth, 0); var matToRight = new Matrix(); matToRight.Translate(laneWidth, 0); var leftTimes = 0; using (var path = hold.GetGraphicsPath(env)) { if (path.IsVisible(p)) { return(true); } while (path.GetBounds().Right > env.LaneRect.Right) { path.Transform(matToLeft); if (path.IsVisible(p)) { return(true); } leftTimes++; } var matToReset = new Matrix(); matToReset.Translate(laneWidth * leftTimes, 0); path.Transform(matToReset); while (path.GetBounds().Left < env.LaneRect.Left) { path.Transform(matToRight); if (path.IsVisible(p)) { return(true); } } } return(false); }
/// <summary> /// 絶対実座標から仮想座標を計算します /// LaneのRangeは(-inf, inf)(RawLaneを計算) /// </summary> /// <param name="env">エディタレーン環境</param> /// <param name="p">実座標(左上原点)</param> /// <param name="beat">拍数のストライド</param> /// <param name="scores"></param> /// <param name="position">計算された仮想座標</param> /// <returns>仮想座標の計算に成功したかどうか</returns> public static bool ConvertRealToVirtual(IReadOnlyEditorLaneEnvironment env, Point p, TimingPosition beat, IReadOnlyList <IReadOnlyScore> scores, out Position position) { p = new Point(p.X - env.PanelRegion.X, p.Y - env.PanelRegion.Y); position = null; if (env.AvailableLaneWidth == 0) { return(false); } var laneLeft = env.SideMargin; var laneRight = laneLeft + env.AvailableLaneWidth; if (!(laneLeft <= p.X && p.X < laneRight)) { return(false); } int lanePos = (int)(((p.X - laneLeft) + env.OffsetXRaw) / env.LaneUnitWidth); if ((p.X - laneLeft) + env.OffsetXRaw < 0) { lanePos--; } var newLanePos = new LanePotision(lanePos); var timing = new TimingPosition(env.TimingUnitHeight.ToUInt(), (env.PanelRegion.Height - p.Y) - (int)env.BottomMargin + env.OffsetY); var accum = new TimingPosition(1, 0); foreach (var score in scores) { var tmp = new TimingPosition(score.BeatDen, (int)score.BeatNum); if (timing < tmp + accum) { break; } accum += tmp; } var cnt = (int)Math.Floor(((timing - accum) / beat).BarRatio); var newTimingPos = new TimingPosition(beat.DivValue, cnt) + accum; position = new Position(newLanePos, newTimingPos); return(true); }
public static void Draw(System.Drawing.Graphics g, IReadOnlyEditorLaneEnvironment env, IReadOnlyList <Score.IReadOnlyScore> scores) { using (var backgroundBrush = new SolidBrush(backgroundColor)) using (var laneBackBrush = new SolidBrush(laneBackColor)) { g.FillRectangle(backgroundBrush, env.PanelRegion); g.FillRectangle(laneBackBrush, env.LaneRect); } using (var penBorder = new Pen(Color.White)) using (var penMain = new Pen(Color.FromArgb(200, Color.White))) using (var penSub = new Pen(Color.FromArgb(130, Color.White))) using (Font myFont = new Font("MS UI Gothic", 10, FontStyle.Bold)) using (var penTimingMain = new Pen(timingMainColor)) { // レーン補助線を描画 var diffX = (int)(env.LaneUnitWidth - env.OffsetX % env.LaneUnitWidth); if (diffX == env.LaneUnitWidth) { diffX = 0; } var curX = diffX + env.LaneRect.Left; var curLane = (diffX + env.OffsetX) / env.LaneUnitWidth; for (; curX <= env.LaneRect.Right; curX += (int)env.LaneUnitWidth, ++curLane) { curLane %= MadcaEnv.LaneCount; if (curLane % env.LaneGroupCount == 0) { g.DrawLine(penMain, new PointF(curX, env.PanelRegion.Y), new PointF(curX, env.PanelRegion.Y + env.AvailableLaneHeight)); var textWidth = System.Windows.Forms.TextRenderer.MeasureText(g, curLane.ToString(), myFont).Width; g.DrawString(curLane.ToString(), myFont, Brushes.White, new PointF(curX - textWidth / 2 + 1.5f, env.PanelRegion.Y + env.AvailableLaneHeight + 5)); continue; } g.DrawLine(penSub, new PointF(curX, env.PanelRegion.Y), new PointF(curX, env.PanelRegion.Y + env.AvailableLaneHeight)); } // 小節線などを描画 if (scores == null) { return; } var offsetTimingMin = new TimingPosition(env.TimingUnitHeight.ToUInt(), env.OffsetY); var offsetTimingMax = new TimingPosition(env.TimingUnitHeight.ToUInt(), env.OffsetY + env.LaneRect.Height); var drawScores = scores.Where(x => !(x.TimingEnd <= offsetTimingMin || offsetTimingMax < x.TimingBegin)); foreach (var score in drawScores) { var y = (int)(env.LaneRect.Bottom - (score.TimingBegin - offsetTimingMin).BarRatio * env.TimingUnitHeight); if (env.LaneRect.Top <= y && y <= env.LaneRect.Bottom) { g.DrawString(scores.IndexOf(score).ToString().PadLeft(3, '0'), myFont, Brushes.White, new Point(env.LaneRect.Left - 28, y - 12)); g.DrawLine(penTimingMain, new Point(env.LaneRect.Left, y), new Point(env.LaneRect.Right, y)); } for (var cnt = 1; cnt < score.BeatNum; ++cnt) { y -= (int)(env.TimingUnitHeight / score.BeatDen); if (env.LaneRect.Top <= y && y <= env.LaneRect.Bottom) { g.DrawLine(penSub, new Point(env.LaneRect.Left, y), new Point(env.LaneRect.Right, y)); } } } } }
public static int NoteHeight => 5; // 決め打ち public static int NoteWidth(int size, IReadOnlyEditorLaneEnvironment env) { return((int)env.LaneUnitWidth * size); }