private CommentUI MakeCommentUI(Comment comment, ref CommentRenderFrameData frame) { // フォントサイズの計算 // 画面サイズの10分の1*ベーススケール*フォントスケール float commentFontScale = 1.0f; switch (comment.SizeMode) { case CommentSizeMode.Normal: commentFontScale = 1.0f; break; case CommentSizeMode.Big: commentFontScale = 1.25f; break; case CommentSizeMode.Small: commentFontScale = 0.75f; break; default: break; } var baseSize = Math.Max(frame.CanvasHeight * BaseCommentSizeRatioByCanvasHeight, 24); const float PixelToPoint = 0.75f; var scaledFontSize = baseSize * frame.FontScale * commentFontScale * PixelToPoint; var commentFontSize = (uint)Math.Ceiling(scaledFontSize); // コメントカラー Color commentColor = default(Color); if (comment.Color == null) { commentColor = frame.CommentDefaultColor; } else { commentColor = comment.Color.Value; } var textBGOffset = Math.Floor(FontSize * TextBGOffsetBias); var commentUI = new CommentUI() { CommentText = comment.CommentText, TextColor = commentColor, BackTextColor = GetShadowColor(commentColor), VideoPosition = comment.VideoPosition, EndPosition = comment.VideoPosition + frame.CommentDisplayDurationVPos, TextBGOffsetX = textBGOffset, TextBGOffsetY = textBGOffset, CommentFontSize = commentFontSize, IsVisible = !comment.IsInvisible, DisplayMode = comment.DisplayMode }; return(commentUI); }
public static uint CalcStreamCommentReachToScreenLeftEdge(CommentUI second, double canvasWidth) { var secondDisplayTime = second.EndPosition - second.VideoPosition; // 1 Vposあたりの secondコメントの移動量 var secondSpeed = (canvasWidth + second.TextWidth) / (float)secondDisplayTime; // 時間 = 距離 ÷ 速さ var timeToSecondCommentWidthMove = (uint)(second.TextWidth / secondSpeed); return(timeToSecondCommentWidthMove); }
private CommentRenderInfo MakeCommentUI(Comment comment, CommentRenderFrameData frame) { // フォントサイズの計算 // 画面サイズの10分の1*ベーススケール*フォントスケール var baseSize = Math.Max(frame.CanvasHeight * BaseCommentSizeRatioByCanvasHeight, 24); const float PixelToPoint = 0.75f; var scaledFontSize = baseSize * frame.FontScale * comment.FontScale * PixelToPoint; comment.FontSize = (uint)Math.Ceiling(scaledFontSize); // フォントの影のオフセット量 comment.TextBGOffset = Math.Floor(FontSize * TextBGOffsetBias); // コメントの終了位置を更新 comment.EndPosition = comment.VideoPosition + frame.CommentDisplayDurationVPos; // コメントカラー if (comment.Color == null) { comment.RealColor = frame.CommentDefaultColor; } else { comment.RealColor = comment.Color.Value; } // コメント背景の色を求める comment.BackColor = GetShadowColor(comment.RealColor); var commentUI = new CommentUI() { DataContext = comment }; return(new CommentRenderInfo() { Comment = comment, CommentUI = commentUI, }); }
private void OnUpdate(TimeSpan elapsedTime) { var frame = GetRenderFrameData(); // 非表示時は処理を行わない if (frame.Visibility == Visibility.Collapsed) { _IsNeedCommentRenderUpdated = true; if (RenderComments.Any()) { foreach (var renderComment in RenderComments) { renderComment.Offset(0).Fade(0).SetDurationForAll(0).Start(); } CommentCanvas.Children.Clear(); RenderComments.Clear(); } return; } if (_IsNeedCommentRenderUpdated) { ResetComments(ref frame); _IsNeedCommentRenderUpdated = false; } // RenderPendingCommentsからコメント表示時間より古いコメントを排除 while (RenderPendingComments.Count != 0) { var tryComment = RenderPendingComments.First(); if (tryComment.VideoPosition + frame.CommentDisplayDurationVPos < frame.CurrentVpos) { RenderPendingComments.Remove(tryComment); } else { break; } } // 表示が完了したコメントを削除 // 表示区間をすぎたコメントを表示対象から削除 // 現在位置より若いコメントはReset時にカットしているのでスルー while (RenderComments.Count > 0) { var renderComment = RenderComments.First(); if (frame.CurrentVpos < renderComment.EndPosition) { break; } renderComment.Offset(0).Fade(0).SetDurationForAll(0).Start(); RenderComments.Remove(renderComment); CommentCanvas.Children.Remove(renderComment); // RenderCommentInfoとCommentUIのインスタンスを使いまわしているため // PrevRenderCommentEachLine_*のリストから不要要素を削除しておかないと // 将来の描画フレームにおいてインスタンスが再有効化された時に // 縦位置決定の処理で問題が発生するようになる if (renderComment.DisplayMode == CommentDisplayMode.Scrolling) { var index = PrevRenderCommentEachLine_Stream.IndexOf(renderComment); if (index >= 0) { PrevRenderCommentEachLine_Stream[index] = null; } } else if (renderComment.DisplayMode == CommentDisplayMode.Top) { var index = PrevRenderCommentEachLine_Top.IndexOf(renderComment); if (index >= 0) { PrevRenderCommentEachLine_Top[index] = null; } } else if (renderComment.DisplayMode == CommentDisplayMode.Bottom) { var index = PrevRenderCommentEachLine_Bottom.IndexOf(renderComment); if (index >= 0) { PrevRenderCommentEachLine_Bottom[index] = null; } } else //if (c.VAlign == VerticalAlignment.Center) { PrevRenderComment_Center = null; } } // RenderPendingCommentsから現在時間までのコメントを順次取り出してRenderCommentsに追加していく while (RenderPendingComments.Count > 0) { var c = RenderPendingComments.First(); if (c.VideoPosition < frame.CurrentVpos) { _RenderCandidateComments.Add(c); RenderPendingComments.Remove(c); } else { break; } } bool isCanAddRenderComment_Stream = true; bool isCanAddRenderComment_Top = true; bool isCanAddRenderComment_Bottom = true; bool isCanAddRenderComment_Center = PrevRenderComment_Center?.IsEndDisplay(frame.CurrentVpos) ?? true; foreach (var comment in _RenderCandidateComments) { if (!frame.IsShowOperationComment && comment.IsOperationCommand) { continue; } // 現フレームでは既に追加不可となっている場合はスキップ if (comment.DisplayMode == CommentDisplayMode.Scrolling) { if (!isCanAddRenderComment_Stream) { continue; } } else if (comment.DisplayMode == CommentDisplayMode.Top) { if (!isCanAddRenderComment_Top) { continue; } } else if (comment.DisplayMode == CommentDisplayMode.Bottom) { if (!isCanAddRenderComment_Bottom) { continue; } } else if (comment.DisplayMode == CommentDisplayMode.Center) { continue; // if (!isCanAddRenderComment_Center) { continue; } } // TODO: NGCommentの判定 if (NGSettings.IsNGComment(comment.CommentText) != null) { Debug.WriteLine("NG: " + comment.CommentText); continue; } if (comment.IsInvisible) { continue; } // 表示対象に登録 var renderComment = MakeCommentUI(comment, ref frame); RenderComments.Add(renderComment); CommentCanvas.Children.Add(renderComment); renderComment.UpdateLayout(); // 初期の縦・横位置を計算 // 縦位置を計算して表示範囲外の場合はそれぞれの表示縦位置での追加をこのフレーム内で打ち切る bool isOutBoundComment = false; if (comment.DisplayMode == CommentDisplayMode.Scrolling) { // 流れるコメントの縦位置を決定 // 前に流れているコメントを走査して挿入可能な高さを判定していく // 前後のコメントが重複なく流せるかを求める int insertPosition = -1; double verticalPos = 8; var currentCommentReachLeftEdgeTime = renderComment.CalcReachLeftEdge(frame.CanvasWidth); for (var i = 0; i < PrevRenderCommentEachLine_Stream.Count; i++) { var prevComment = PrevRenderCommentEachLine_Stream[i]; // 先行コメントのテキストが画面内に完全に収まっている場合 // かつ // 追加したいコメントが画面左端に到達した時間が // 先行しているコメントの表示終了時間を超える場合 // コリジョンしない if (prevComment == null || (prevComment.CalcTextShowRightEdgeTime(frame.CanvasWidth) < frame.CurrentVpos && prevComment.EndPosition < currentCommentReachLeftEdgeTime) ) { // コリジョンしない // 追加可能 insertPosition = i; break; } else { // コリジョンする // 追加できない verticalPos += prevComment.TextHeight + prevComment.TextHeight * CommentVerticalMarginRatio; } } // 画面下部に少しでも文字がはみ出るようなら範囲外 isOutBoundComment = (verticalPos + renderComment.TextHeight) > frame.CanvasHeight; if (isOutBoundComment) { isCanAddRenderComment_Stream = false; } else { // 最初は右端に配置 double?initialVPos = renderComment.GetPosition(frame.CanvasWidth, frame.CurrentVpos) ?? frame.CanvasWidth; renderComment.Opacity = 1.0; if (frame.PlaybackState == MediaPlaybackState.Playing) { renderComment .Offset((float)initialVPos.Value, duration: 0) .Then() .Offset(-(float)renderComment.TextWidth, duration: (renderComment.EndPosition - frame.CurrentVpos) * 10u * frame.PlaybackRateInverse, easingType: EasingType.Linear) .Start(); } else { renderComment .Offset((float)initialVPos.Value, duration: 0) .Start(); } Canvas.SetTop(renderComment, verticalPos); if (insertPosition == -1) { // 最後尾に追加 PrevRenderCommentEachLine_Stream.Add(renderComment); } else { // 指定の位置に追加 PrevRenderCommentEachLine_Stream[insertPosition] = renderComment; } isCanAddRenderComment_Stream = (verticalPos + (renderComment.TextHeight + renderComment.TextHeight * CommentVerticalMarginRatio)) < frame.CanvasHeight; } } else { if (comment.DisplayMode == CommentDisplayMode.Top) { // 上に位置する場合の縦位置の決定 int insertPosition = -1; double verticalPos = 8; for (var i = 0; i < PrevRenderCommentEachLine_Top.Count; i++) { var prevComment = PrevRenderCommentEachLine_Top[i]; if (prevComment == null || prevComment.EndPosition < frame.CurrentVpos) { insertPosition = i; break; } else { verticalPos += prevComment.TextHeight + prevComment.TextHeight * CommentVerticalMarginRatio; } } // 上コメが画面下部からはみ出す場合には範囲外 isOutBoundComment = (verticalPos + renderComment.TextHeight) > frame.CanvasHeight; if (isOutBoundComment) { isCanAddRenderComment_Top = false; } else { Canvas.SetTop(renderComment, verticalPos); if (insertPosition == -1) { // 最後尾に追加 PrevRenderCommentEachLine_Top.Add(renderComment); } else { // 指定の位置に追加 PrevRenderCommentEachLine_Top[insertPosition] = renderComment; } isCanAddRenderComment_Top = (verticalPos + (renderComment.TextHeight + renderComment.TextHeight * CommentVerticalMarginRatio)) < frame.CanvasHeight; } } else if (comment.DisplayMode == CommentDisplayMode.Bottom) { // 下に位置する場合の縦位置の決定 int insertPosition = -1; double verticalPos = frame.CanvasHeight - renderComment.TextHeight - BottomCommentMargin; for (var i = 0; i < PrevRenderCommentEachLine_Bottom.Count; i++) { var prevComment = PrevRenderCommentEachLine_Bottom[i]; if (prevComment == null || prevComment.EndPosition < frame.CurrentVpos) { insertPosition = i; break; } else { verticalPos -= (prevComment.TextHeight + prevComment.TextHeight * CommentVerticalMarginRatio); } } // 下コメが画面上部からはみ出す場合には範囲外 isOutBoundComment = verticalPos < 0; if (isOutBoundComment) { isCanAddRenderComment_Bottom = false; } else { Canvas.SetTop(renderComment, verticalPos); if (insertPosition == -1) { // 最後尾に追加 PrevRenderCommentEachLine_Bottom.Add(renderComment); } else { // 指定の位置に追加 PrevRenderCommentEachLine_Bottom[insertPosition] = renderComment; } isCanAddRenderComment_Bottom = (verticalPos - (renderComment.TextHeight + renderComment.TextHeight * CommentVerticalMarginRatio)) > 0; } } else //if (comment.VAlign == VerticalAlignment.Center) { Canvas.SetTop(renderComment, frame.CanvasHeight * 0.5f - renderComment.TextHeight * 0.5f); PrevRenderComment_Center = renderComment; isCanAddRenderComment_Center = false; } // オーナーコメントの場合は優先して表示されるように if (comment.IsOwnerComment) { Canvas.SetZIndex(renderComment, OWNER_COMMENT_Z_INDEX); } if (!isOutBoundComment) { var left = (float)frame.HalfCanvasWidth - (int)(renderComment.TextWidth * 0.5f); renderComment.Offset(offsetX: left, duration: 0).Start(); } } if (isOutBoundComment) { // 追加してしまったRenderComments等からは削除しておく RenderComments.Remove(renderComment); CommentCanvas.Children.Remove(renderComment); renderComment.DataContext = null; } } _RenderCandidateComments.Clear(); }
private CommentUI MakeCommentUI(Comment comment, ref CommentRenderFrameData frame) { if (!string.IsNullOrEmpty(comment.Mail)) { var filteredCommands = comment.Mail.Split(' ').Where(x => !PlayerSettings.FilteringCommands.Contains(x)); var commandActions = MailToCommandHelper.MakeCommandActions(filteredCommands); foreach (var action in commandActions) { action(comment); } } // フォントサイズの計算 // 画面サイズの10分の1*ベーススケール*フォントスケール float commentFontScale = 1.0f; switch (comment.SizeMode) { case CommentSizeMode.Normal: commentFontScale = 1.0f; break; case CommentSizeMode.Big: commentFontScale = 1.25f; break; case CommentSizeMode.Small: commentFontScale = 0.75f; break; default: break; } var baseSize = Math.Max(frame.CanvasHeight * BaseCommentSizeRatioByCanvasHeight, 24); const float PixelToPoint = 0.75f; var scaledFontSize = baseSize * frame.FontScale * commentFontScale * PixelToPoint; var commentFontSize = (uint)Math.Ceiling(scaledFontSize); // コメントカラー Color commentColor = default(Color); if (comment.Color == null) { commentColor = frame.CommentDefaultColor; } else { commentColor = comment.Color.Value; } var textBGOffset = Math.Floor(FontSize * TextBGOffsetBias); string commentText = comment.CommentText; if (PlayerSettings.CommentGlassMowerEnable) { if (PlayerSettings.TryGlassMower(comment.CommentText, out commentText)) { Debug.WriteLine($"GlassMower: {comment.CommentText} -----> {commentText}"); } } var commentUI = new CommentUI() { CommentText = commentText, TextColor = commentColor, BackTextColor = GetShadowColor(commentColor), VideoPosition = comment.VideoPosition, EndPosition = comment.VideoPosition + frame.CommentDisplayDurationVPos, TextBGOffsetX = textBGOffset, TextBGOffsetY = textBGOffset, CommentFontSize = commentFontSize, IsVisible = !comment.IsInvisible, DisplayMode = comment.DisplayMode }; return(commentUI); }
public static bool IsStreamCommentColide(CommentUI first, CommentUI second, double canvasWidth) { return(first.EndPosition > CalcStreamCommentReachToScreenLeftEdge(second, canvasWidth)); }