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); }
private CommentRenderFrameData GetRenderFrameData() { CommentRenderFrameData frame = null; var currentVpos = (uint)Math.Floor(VideoPosition.TotalMilliseconds * 0.1); var canvasWidth = (int)CommentCanvas.ActualWidth; var canvasHeight = (uint)CommentCanvas.ActualHeight; var halfCanvasWidth = canvasWidth / 2; var fontScale = (float)CommentSizeScale; var commentDefaultColor = CommentDefaultColor; var commentDisplayDuration = GetCommentDisplayDurationVposUnit(); frame = new CommentRenderFrameData() { CurrentVpos = currentVpos, CanvasWidth = canvasWidth, CanvasHeight = canvasHeight, HalfCanvasWidth = halfCanvasWidth, FontScale = fontScale, CommentDefaultColor = commentDefaultColor, CommentDisplayDuration = commentDisplayDuration, Visibility = Visibility, }; return(frame); }
private CommentRenderFrameData GetRenderFrameData() { var frameData = new CommentRenderFrameData(); frameData.CommentDisplayDuration = DefaultDisplayDuration; frameData.PlaybackState = MediaPlayer.PlaybackSession.PlaybackState; frameData.CommentDefaultColor = CommentDefaultColor; frameData.CurrentVpos = (uint)Math.Floor((VideoPosition + VideoPositionOffset).TotalMilliseconds * 0.1); frameData.CanvasWidth = (int)CommentCanvas.ActualWidth; frameData.CanvasHeight = (uint)CommentCanvas.ActualHeight; frameData.HalfCanvasWidth = CommentCanvas.ActualWidth * 0.5; frameData.FontScale = (float)CommentSizeScale; frameData.CommentDisplayDurationVPos = GetCommentDisplayDurationVposUnit(); frameData.Visibility = Visibility; frameData.PlaybackRate = MediaPlayer.PlaybackSession.PlaybackRate; frameData.PlaybackRateInverse = 1d / frameData.PlaybackRate; frameData.IsShowOperationComment = IsShowNicoLiveOperationComment; return(frameData); }
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 ResetComments(ref CommentRenderFrameData frame) { Debug.WriteLine("Comment Reset"); foreach (var renderComment in RenderComments) { renderComment.Offset(0).Fade(0).SetDurationForAll(0).Start(); } RenderPendingComments.Clear(); RenderComments.Clear(); CommentCanvas.Children.Clear(); PrevRenderCommentEachLine_Stream.Clear(); PrevRenderCommentEachLine_Top.Clear(); PrevRenderCommentEachLine_Bottom.Clear(); if (Comments == null) { return; } // 現在時間-コメント表示時間から始まるコメントを描画待機コメントとして再配置 var currentVideoPos = frame.CurrentVpos; var comments = new List <Comment>(Comments.Cast <Comment>()); comments.Sort((x, y) => (int)(x.VideoPosition - y.VideoPosition)); RenderPendingComments.AddRange(comments); // あとは毎フレーム処理に任せる _RealVideoPosition = DateTime.Now; }
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); }
private int CalcAndRegisterCommentVerticalPosition(CommentUI commentUI, CommentRenderFrameData frame) { const double TextSizeToMargin = 0.425; // コメントの縦位置ごとの「空き段」を管理するリストを探す List <CommentUI> verticalAlignList; VerticalAlignment?_valign = (commentUI.DataContext as Comment).VAlign; int?commentVerticalPos = null; int totalHeight = 0; // TrimFromBaselineを指定しているため、下コメントに余白を追加 if (_valign.HasValue && _valign.Value == VerticalAlignment.Bottom) { totalHeight += BottomCommentMargin; } else { // 一番上の余白、上にコメントがこないので半分(* 0.5)として計算 totalHeight += (int)(commentUI.DesiredSize.Height * TextSizeToMargin * 0.5); } // 流れるコメント用の計算パラメータ // for文の中だと何度も計算する場合があるので // forスコープの外に出してます var currentVpos = frame.CurrentVpos; var canvasWidth = frame.CanvasWidth; var displayDuration = GetCommentDisplayDurationVposUnit(); var canvasByCommentWidthRatio = canvasWidth / (commentUI.DesiredSize.Width + canvasWidth); var reachToLeftTime = (uint)Math.Floor(displayDuration * canvasByCommentWidthRatio); var currentTimeBaseReachToLeftTime = commentUI.CommentData.VideoPosition + reachToLeftTime; var displayEndTime = commentUI.CommentData.EndPosition; if (_valign.HasValue && _valign.Value == VerticalAlignment.Bottom) { verticalAlignList = BottomAlignNextVerticalPosition; for (int i = 0; i < verticalAlignList.Count; ++i) { var next = verticalAlignList[i]; if (next == null) { commentVerticalPos = (int)this.ActualHeight - (int)commentUI.DesiredSize.Height - totalHeight; verticalAlignList[i] = commentUI; } else { totalHeight += (int)next.DesiredSize.Height + CommentVerticalMargin + (int)(next.DesiredSize.Height * TextSizeToMargin); } } if (!commentVerticalPos.HasValue) { commentVerticalPos = (int)this.ActualHeight - (int)commentUI.DesiredSize.Height - totalHeight; verticalAlignList.Add(commentUI); } } else if (_valign.HasValue && _valign.Value == VerticalAlignment.Top) { // 上コメ verticalAlignList = TopAlignNextVerticalPosition; for (int i = 0; i < verticalAlignList.Count; ++i) { var next = verticalAlignList[i]; if (next == null) { verticalAlignList[i] = commentUI; commentVerticalPos = totalHeight; } else { totalHeight += (int)next.DesiredSize.Height + CommentVerticalMargin + (int)(next.DesiredSize.Height * TextSizeToMargin); } } if (!commentVerticalPos.HasValue) { commentVerticalPos = totalHeight; verticalAlignList.Add(commentUI); } } else { // 流れるコメント verticalAlignList = NextVerticalPosition; for (int i = 0; i < verticalAlignList.Count; ++i) { var next = verticalAlignList[i]; if (next == null) { // 流れるコメントを前のコメントと被らないようにする // 前コメントの表示完了時間と追加したいコメントの表示完了時間を比較し // 追加したいコメントの表示完了時間 // 前のコメントがない場合は、常に追加可能 if (LastCommentDisplayEndTime.Count <= i) { verticalAlignList[i] = commentUI; commentVerticalPos = totalHeight; LastCommentDisplayEndTime.Add(new LastStreamedComment() { EndTime = Math.Max(displayEndTime + 5, 0), Comment = commentUI }); break; } // 前のコメントが有る場合、 // 前コメの表示終了時間より後に終わる場合はコメ追加可能 else if (LastCommentDisplayEndTime[i].EndTime < currentTimeBaseReachToLeftTime) { verticalAlignList[i] = commentUI; commentVerticalPos = totalHeight; LastCommentDisplayEndTime[i] = new LastStreamedComment() { EndTime = Math.Max(displayEndTime + 5, 0), Comment = commentUI }; break; } else { var prevComment = LastCommentDisplayEndTime[i].Comment; totalHeight += (int)prevComment.DesiredSize.Height + CommentVerticalMargin + (int)(prevComment.DesiredSize.Height * TextSizeToMargin); //Debug.WriteLine("前コメと衝突を回避 " + prevComment.CommentData.CommentText); } } else { totalHeight += (int)next.DesiredSize.Height + CommentVerticalMargin + (int)(next.DesiredSize.Height * TextSizeToMargin); } } if (!commentVerticalPos.HasValue) { commentVerticalPos = totalHeight; verticalAlignList.Add(commentUI); } } return(commentVerticalPos.Value); }
private void PlaybackSession_PositionChanged(MediaPlaybackSession sender, object args) { _dispatcherQueue.TryEnqueue(() => { if (_nowWindowSizeChanging) { return; } var prev = PlaybackState; PlaybackState = sender?.PlaybackState ?? null; if (prev != PlaybackState) { Debug.WriteLine("state changed " + PlaybackState); ResetScrollCommentsAnimation(GetRenderFrameData()); } TimeSpan currentVpos = CurrentVPos; if (Math.Abs((float)(currentVpos - _prevPosition).TotalSeconds) > 0.5f) { Debug.WriteLine("seeked! position changed"); ResetComments(); } else { // 表示期間を過ぎたコメントを削除 for (int i = 0; i < CommentCanvas.Children.Count; i++) { var comment = CommentCanvas.Children[i] as CommentUI; if (comment.EndPosition <= currentVpos) { RemoveCommentFromCanvas(comment.Comment); --i; } else { break; } } // 追加待機中のコメントをチェック int count = 0; CommentRenderFrameData frame = null; for (int i = 0; i < _pendingRenderComments.Count; i++) { if (count >= 10) { break; } count++; var comment = _pendingRenderComments[i]; if (comment.VideoPosition <= (currentVpos + TimeSpan.FromSeconds(1))) { frame ??= GetRenderFrameData(); _pendingRenderComments.RemoveAt(i); --i; AddCommentToCanvas(comment, frame); } else { break; } } } // コメントの再描画完了時間を前回位置として記録する // currentVposを使うとシーク判定の時間以上にコメント描画の処理に時間が掛かった場合に // コメント再描画のループが発生してしまう。 _prevPosition = CurrentVPos; }); }