示例#1
0
        public override void Draw()
        {
            if (video == null)
            {
                return;
            }

            if (!stopped && !paused)
            {
                var nextFrame = 0;
                if (video.HasAudio && !Game.Sound.DummyEngine)
                {
                    nextFrame = (int)float2.Lerp(0, video.Frames, Game.Sound.VideoSeekPosition * invLength);
                }
                else
                {
                    nextFrame = video.CurrentFrame + 1;
                }

                // Without the 2nd check the sound playback sometimes ends before the final frame is displayed which causes the player to be stuck on the first frame
                if (nextFrame > video.Frames || nextFrame < video.CurrentFrame)
                {
                    Stop();
                    return;
                }

                var skippedFrames = 0;
                while (nextFrame > video.CurrentFrame)
                {
                    video.AdvanceFrame();
                    videoSprite.Sheet.GetTexture().SetData(video.FrameData);
                    skippedFrames++;
                }

                if (skippedFrames > 1)
                {
                    Log.Write("perf", "VqaPlayer : {0} skipped {1} frames at position {2}", cachedVideo, skippedFrames, video.CurrentFrame);
                }
            }

            WidgetUtils.DrawSprite(videoSprite, videoOrigin, videoSize);

            if (DrawOverlay)
            {
                // Create the scan line grid to render over the video
                // To avoid aliasing, this must be an integer number of screen pixels.
                // A few complications to be aware of:
                // - The video may have a different aspect ratio to the widget RenderBounds
                // - The RenderBounds coordinates may be a non-integer scale of the screen pixel size
                // - The screen pixel size may change while the video is playing back
                //   (user moves a window between displays with different DPI on macOS)
                var scale = Game.Renderer.WindowScale;
                if (overlaySheet == null || overlayScale != scale)
                {
                    overlaySheet?.Dispose();

                    // Calculate the scan line height by converting the video scale (copied from Open()) to screen
                    // pixels, halving it (scan lines cover half the pixel height), and rounding to the nearest integer.
                    var videoScale    = Math.Min((float)RenderBounds.Width / video.Width, RenderBounds.Height / (video.Height * AspectRatio));
                    var halfRowHeight = (int)(videoScale * scale / 2 + 0.5f);

                    // The overlay can be minimally stored in a 1px column which is stretched to cover the full screen
                    var overlayHeight    = (int)(RenderBounds.Height * scale / halfRowHeight);
                    var overlaySheetSize = new Size(1, Exts.NextPowerOf2(overlayHeight));
                    var overlay          = new byte[4 * Exts.NextPowerOf2(overlayHeight)];
                    overlaySheet = new Sheet(SheetType.BGRA, overlaySheetSize);

                    // Every second pixel is the scan line - set alpha to 128 to make the lines less harsh
                    for (var i = 3; i < 4 * overlayHeight; i += 8)
                    {
                        overlay[i] = 128;
                    }

                    overlaySheet.GetTexture().SetData(overlay, overlaySheetSize.Width, overlaySheetSize.Height);
                    overlaySprite = new Sprite(overlaySheet, new Rectangle(0, 0, 1, overlayHeight), TextureChannel.RGBA);

                    // Overlay origin must be rounded to the nearest screen pixel to prevent aliasing
                    overlayOrigin = new float2((int)(RenderBounds.X * scale + 0.5f), (int)(RenderBounds.Y * scale + 0.5f)) / scale;
                    overlaySize   = new float2(RenderBounds.Width, overlayHeight * halfRowHeight / scale);
                    overlayScale  = scale;
                }

                WidgetUtils.DrawSprite(overlaySprite, overlayOrigin, overlaySize);
            }
        }