Exemple #1
0
        public GLWindow()
            : base(1280, 720, new GraphicsMode(new ColorFormat(32), 0, 8, 0, ColorFormat.Empty),
                   "Line Rider: Advanced", GameWindowFlags.Default, DisplayDevice.Default)
        {
            if (_instance != null)
            {
                throw new InvalidOperationException();
            }

            SafeFrameBuffer.Initialize();
            _instance = this;
            StaticRenderer.InitializeCircles();
            _penciltool           = new PencilTool();
            _linetool             = new LineTool();
            _erasertool           = new EraserTool();
            _handtool             = new HandTool();
            _lineadjusttool       = new LineAdjustTool();
            SelectedTool          = _penciltool;
            Track                 = new GLTrack();
            VSync                 = VSyncMode.Off;
            Context.ErrorChecking = true;
            WindowBorder          = WindowBorder.Resizable;
            RenderFrame          += (o, e) => { Render(); };
            UpdateFrame          += (o, e) => { GameUpdate(); };
            GameService.Initialize(this);
        }
 public MainWindow()
     : base(
         1280,
         720,
         new GraphicsMode(new ColorFormat(24), 0, 0, 0, ColorFormat.Empty),
         "Line Rider: Advanced",
         GameWindowFlags.Default,
         DisplayDevice.Default,
         2,
         0,
         GraphicsContextFlags.Default)
 {
     SafeFrameBuffer.Initialize();
     PencilTool            = new PencilTool();
     LineTool              = new LineTool();
     EraserTool            = new EraserTool();
     HandTool              = new HandTool();
     MoveTool              = new MoveTool();
     SelectedTool          = PencilTool;
     Track                 = new Editor();
     VSync                 = VSyncMode.On;
     Context.ErrorChecking = false;
     WindowBorder          = WindowBorder.Resizable;
     RenderFrame          += (o, e) => { Render(); };
     UpdateFrame          += (o, e) => { GameUpdate(); };
     GameService.Initialize(this);
     RegisterHotkeys();
 }
Exemple #3
0
        public static byte[] GrabScreenshot(MainWindow game, int frontbuffer, bool yflip = false)
        {
            if (GraphicsContext.CurrentContext == null)
            {
                throw new GraphicsContextMissingException();
            }
            var backbuffer = game.MSAABuffer.Framebuffer;

            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.ReadFramebuffer, backbuffer);
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.DrawFramebuffer, frontbuffer);
            if (yflip) //Screenshots are captured upside-down for some reason but this is corrected during video encoding, so flip here for a correctly oriented screenshot
            {
                SafeFrameBuffer.BlitFramebuffer(0, 0, game.RenderSize.Width, game.RenderSize.Height,
                                                0, game.RenderSize.Height, game.RenderSize.Width, 0,
                                                ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
            }
            else
            {
                SafeFrameBuffer.BlitFramebuffer(0, 0, game.RenderSize.Width, game.RenderSize.Height,
                                                0, 0, game.RenderSize.Width, game.RenderSize.Height,
                                                ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
            }
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.ReadFramebuffer, frontbuffer);

            GL.ReadPixels(0, 0, game.RenderSize.Width, game.RenderSize.Height,
                          OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, _screenshotbuffer);
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, backbuffer);
            return(_screenshotbuffer);
        }
Exemple #4
0
        public static byte[] GrabScreenshot(MainWindow game, int frontbuffer)
        {
            if (GraphicsContext.CurrentContext == null)
            {
                throw new GraphicsContextMissingException();
            }
            var backbuffer = game.MSAABuffer.Framebuffer;

            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.ReadFramebuffer, backbuffer);
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.DrawFramebuffer, frontbuffer);
            SafeFrameBuffer.BlitFramebuffer(0, 0, game.RenderSize.Width, game.RenderSize.Height,
                                            0, 0, game.RenderSize.Width, game.RenderSize.Height,
                                            ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.ReadFramebuffer, frontbuffer);

            GL.ReadPixels(0, 0, game.RenderSize.Width, game.RenderSize.Height,
                          OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, _screenshotbuffer);
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, backbuffer);
            return(_screenshotbuffer);
        }
Exemple #5
0
        public static void RecordTrack(MainWindow game, bool is1080P, bool smooth, bool music)
        {
            var flag = game.Track.GetFlag();

            if (flag == null)
            {
                return;
            }
            var resolution = new Size(is1080P ? 1920 : 1280, is1080P ? 1080 : 720);
            var oldsize    = game.RenderSize;
            var invalid    = false;

            using (var trk = game.Track.CreateTrackReader())
            {
                Recording = true;
                game.Track.Reset();
                Recording1080p = is1080P;

                //Set colors back to default for triggers
                linerider.Utils.Constants.TriggerBGColor               = new Color4((byte)game.Track.StartingBGColorR, (byte)game.Track.StartingBGColorG, (byte)game.Track.StartingBGColorB, (byte)255);
                linerider.Utils.Constants.StaticTriggerBGColor         = new Color4((byte)game.Track.StartingBGColorR, (byte)game.Track.StartingBGColorG, (byte)game.Track.StartingBGColorB, (byte)255);
                linerider.Utils.Constants.StaticTriggerLineColorChange = Color.FromArgb(255, game.Track.StartingLineColorR, game.Track.StartingLineColorG, game.Track.StartingLineColorB);
                linerider.Utils.Constants.TriggerLineColorChange       = Color.FromArgb(255, game.Track.StartingLineColorR, game.Track.StartingLineColorG, game.Track.StartingLineColorB);

                var state = game.Track.GetStart();
                var frame = flag.FrameID;
                game.Canvas.SetCanvasSize(game.RenderSize.Width, game.RenderSize.Height);
                game.Canvas.Layout();

                if (frame > 400) //many frames, will likely lag the game. Update the window as a fallback.
                {
                    game.Title = Program.WindowTitle + " [Validating flag]";
                    game.ProcessEvents();
                }
                for (var i = 0; i < frame; i++)
                {
                    state = trk.TickBasic(state);
                }
                for (var i = 0; i < state.Body.Length; i++)
                {
                    if (state.Body[i].Location != flag.State.Body[i].Location ||
                        state.Body[i].Previous != flag.State.Body[i].Previous)
                    {
                        invalid = true;
                        break;
                    }
                }
                var frontbuffer = SafeFrameBuffer.GenFramebuffer();
                SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, frontbuffer);

                var rbo2 = SafeFrameBuffer.GenRenderbuffer();
                SafeFrameBuffer.BindRenderbuffer(RenderbufferTarget.Renderbuffer, rbo2);
                SafeFrameBuffer.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Rgb8, resolution.Width, resolution.Height);
                SafeFrameBuffer.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, rbo2);

                SafeFrameBuffer.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
                if (!invalid)
                {
                    _screenshotbuffer = new byte[game.RenderSize.Width * game.RenderSize.Height * 3];// 3 bytes per pixel
                    string errormessage = "An unknown error occured during recording.";
                    game.Title = Program.WindowTitle + " [Recording | Hold ESC to cancel]";
                    game.ProcessEvents();
                    var filename    = Program.UserDirectory + game.Track.Name + ".mp4";
                    var flagbackup  = flag;
                    var hardexit    = false;
                    var recmodesave = Settings.Local.RecordingMode;
                    Settings.Local.RecordingMode = true;
                    game.Track.StartIgnoreFlag();
                    game.Render();
                    var dir = Program.UserDirectory + game.Track.Name + "_rec";
                    if (!Directory.Exists(dir))
                    {
                        Directory.CreateDirectory(dir);
                    }
                    var firstframe = GrabScreenshot(game, frontbuffer);
                    SaveScreenshot(game.RenderSize.Width, game.RenderSize.Height, firstframe, dir + Path.DirectorySeparatorChar + "tmp" + 0 + ".png");
                    int framecount = smooth ? ((frame + 1) * 60) / 40 : frame + 1; //Add a extra frame

                    double    frametime = 0;
                    Stopwatch sw        = Stopwatch.StartNew();
                    for (var i = 0; i < framecount; i++)
                    {
                        if (hardexit)
                        {
                            break;
                        }
                        if (smooth)
                        {
                            var oldspot = frametime;
                            frametime += 40f / 60f;
                            if (i == 0)
                            {
                                //bugfix:
                                //frame blending uses the previous frame.
                                //so the first frame would be recorded twice,
                                //instead of blended
                                game.Track.Update(1);
                            }
                            else if ((int)frametime != (int)oldspot)
                            {
                                game.Track.Update(1);
                            }
                            var blend = frametime - Math.Truncate(frametime);
                            game.Render((float)blend);
                        }
                        else
                        {
                            game.Track.Update(1);
                            game.Render();
                        }
                        try
                        {
                            var screenshot = GrabScreenshot(game, frontbuffer);
                            SaveScreenshot(game.RenderSize.Width, game.RenderSize.Height, screenshot, dir + Path.DirectorySeparatorChar + "tmp" + (i + 1) + ".png");
                        }
                        catch
                        {
                            hardexit     = true;
                            errormessage = "An error occured when saving the frame.";
                        }

                        if (Keyboard.GetState()[Key.Escape])
                        {
                            hardexit     = true;
                            errormessage = "The user manually cancelled recording.";
                        }
                        if (sw.ElapsedMilliseconds > 500)
                        {
                            game.Title = string.Format("{0} [Recording {1:P} | Hold ESC to cancel]", Program.WindowTitle, i / (double)framecount);
                            game.ProcessEvents();
                        }
                    }
                    game.ProcessEvents();

                    if (!hardexit)
                    {
                        var parameters = new FFMPEGParameters();
                        parameters.AddOption("framerate", smooth ? "60" : "40");
                        parameters.AddOption("i", "\"" + dir + Path.DirectorySeparatorChar + "tmp%d.png" + "\"");
                        if (music && !string.IsNullOrEmpty(game.Track.Song.Location) && game.Track.Song.Enabled)
                        {
                            var fn = Program.UserDirectory + "Songs" +
                                     Path.DirectorySeparatorChar +
                                     game.Track.Song.Location;

                            parameters.AddOption("ss", game.Track.Song.Offset.ToString(Program.Culture));
                            parameters.AddOption("i", "\"" + fn + "\"");
                            parameters.AddOption("c:a", "aac");
                        }
                        double duration = framecount / (smooth ? 60.0 : 40.0);
                        parameters.AddOption("t", duration.ToString(Program.Culture));
                        parameters.AddOption("vf", "vflip");//we save images upside down expecting ffmpeg to flip more efficiently.
                        // ffmpeg x264 encoding doc:
                        // https://trac.ffmpeg.org/wiki/Encode/H.264
                        parameters.AddOption("c:v", "libx264");
                        // we don't care _too_ much about filesize
                        parameters.AddOption("preset", "fast");
                        parameters.AddOption("crf", "17");
                        // increase player compatibility:
                        parameters.AddOption("pix_fmt", "yuv420p");
                        // this optimizes the encoding for animation
                        // how well lr fits into that category i'm not sure.
                        parameters.AddOption("tune", "animation");

                        parameters.OutputFilePath = filename;
                        var failed = false;
                        if (File.Exists(filename))
                        {
                            try
                            {
                                File.Delete(filename);
                            }
                            catch
                            {
                                Program.NonFatalError("A file with the name " + game.Track.Name + ".mp4 already exists");
                                failed       = true;
                                errormessage = "Cannot replace a file of the existing name " + game.Track.Name + ".mp4.";
                            }
                        }
                        if (!failed)
                        {
                            game.Title = Program.WindowTitle + " [Encoding Video | 0%]";
                            game.ProcessEvents();
                            try
                            {
                                FFMPEG.Execute(parameters, (string s) =>
                                {
                                    int idx = s.IndexOf("frame=", StringComparison.InvariantCulture);
                                    if (idx != -1)
                                    {
                                        idx += "frame=".Length;
                                        for (; idx < s.Length; idx++)
                                        {
                                            if (char.IsNumber(s[idx]))
                                            {
                                                break;
                                            }
                                        }
                                        var space = s.IndexOf(" ", idx, StringComparison.InvariantCulture);
                                        if (space != -1)
                                        {
                                            var sub       = s.Substring(idx, space - idx);
                                            var parsedint = -1;
                                            if (int.TryParse(sub, out parsedint))
                                            {
                                                game.Title = Program.WindowTitle + string.Format(" [Encoding Video | {0:P} | Hold ESC to cancel]", parsedint / (double)framecount);
                                                game.ProcessEvents();
                                                if (Keyboard.GetState()[Key.Escape])
                                                {
                                                    hardexit     = true;
                                                    errormessage = "The user manually cancelled recording.";
                                                    return(false);
                                                }
                                            }
                                        }
                                    }
                                    return(true);
                                });
                            }
                            catch (Exception e)
                            {
                                linerider.Utils.ErrorLog.WriteLine(
                                    "ffmpeg error" + Environment.NewLine + e);
                                hardexit     = true;
                                errormessage =
                                    "An ffmpeg error occured.\n" + e.Message;
                            }
                        }
                    }
                    try
                    {
                        Directory.Delete(dir, true);
                    }
                    catch
                    {
                        Program.NonFatalError("Unable to delete " + dir);
                    }
                    if (hardexit)
                    {
                        try
                        {
                            File.Delete(filename);
                        }
                        catch
                        {
                            Program.NonFatalError("Unable to delete " + filename);
                        }
                    }
                    Settings.Local.RecordingMode = recmodesave;
                    game.Title = Program.WindowTitle;
                    game.Track.Stop();
                    game.ProcessEvents();
                    var openwindows = game.Canvas.GetOpenWindows();
                    foreach (var window in openwindows)
                    {
                        var w = window as WindowControl;
                        w?.Close();
                    }
                    if (File.Exists(filename))
                    {
                        AudioService.Beep();
                    }
                    else
                    {
                        game.Canvas.ShowError(errormessage);
                    }
                }
                SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
                SafeFrameBuffer.DeleteFramebuffer(frontbuffer);
                SafeFrameBuffer.DeleteRenderbuffers(1, new[] { rbo2 });
                game.RenderSize = oldsize;
                Recording       = false;

                game.Canvas.SetSize(game.RenderSize.Width, game.RenderSize.Height);
                _screenshotbuffer = null;
            }
        }
Exemple #6
0
        public static void RecordScreenshot(MainWindow game)
        {
            var resolution        = new Size(Settings.ScreenshotWidth, Settings.ScreenshotHeight);
            var oldsize           = game.RenderSize;
            var oldZoomMultiplier = Settings.ZoomMultiplier;
            var oldHitTest        = Settings.Editor.HitTest;

            if (Settings.Recording.ResIndZoom)
            {
                Settings.ZoomMultiplier *= game.ClientSize.Width > game.ClientSize.Height * 16 / 9 ? (float)Settings.ScreenshotWidth / (float)game.ClientSize.Width : (float)Settings.ScreenshotHeight / (float)game.ClientSize.Height;
            }
            Settings.Editor.HitTest = Settings.Recording.ShowHitTest;
            game.Canvas.Scale       = Settings.ZoomMultiplier / oldZoomMultiplier; //Divide just in case anyone modifies the zoom multiplier to not be 1

            using (var trk = game.Track.CreateTrackReader())
            {
                RecordingScreenshot = true;

                game.Canvas.SetCanvasSize(game.RenderSize.Width, game.RenderSize.Height);
                game.Canvas.Layout();

                var frontbuffer = SafeFrameBuffer.GenFramebuffer();
                SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, frontbuffer);

                var rbo2 = SafeFrameBuffer.GenRenderbuffer();
                SafeFrameBuffer.BindRenderbuffer(RenderbufferTarget.Renderbuffer, rbo2);
                SafeFrameBuffer.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Rgb8, resolution.Width, resolution.Height);
                SafeFrameBuffer.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, rbo2);

                SafeFrameBuffer.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);

                _screenshotbuffer = new byte[game.RenderSize.Width * game.RenderSize.Height * 3];// 3 bytes per pixel
                game.Title        = Program.WindowTitle + " [Capturing Screenshot]";
                game.ProcessEvents();

                string filename;

                if (game.Track.Name == Constants.DefaultTrackName)
                {
                    filename = Program.UserDirectory + "Untitled Track" + ".png";
                }
                else
                {
                    filename = Program.UserDirectory + game.Track.Name + ".png";
                }

                var recmodesave = Settings.Local.RecordingMode;
                Settings.Local.RecordingMode = true;
                game.Render();
                var screenshotframe = GrabScreenshot(game, frontbuffer, true);
                SaveScreenshot(game.RenderSize.Width, game.RenderSize.Height, screenshotframe, filename);

                SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, 0); //Delete the FBOs
                SafeFrameBuffer.DeleteFramebuffer(frontbuffer);
                SafeFrameBuffer.DeleteRenderbuffers(1, new[] { rbo2 });

                RecordingScreenshot = false;

                game.RenderSize         = oldsize;
                Settings.ZoomMultiplier = oldZoomMultiplier;
                game.Title = Program.WindowTitle;
                Settings.Local.RecordingMode = recmodesave;
                Settings.Editor.HitTest      = oldHitTest;

                game.Canvas.SetSize(game.RenderSize.Width, game.RenderSize.Height);
                game.Canvas.Scale = 1.0f;
                _screenshotbuffer = null;
            }
        }
Exemple #7
0
        public static void RecordTrack(GLWindow game, bool is1080P)
        {
            var flag = game.Track.GetFlag();

            if (flag == null)
            {
                return;
            }
            var resolution = new Size(is1080P ? 1920 : 1280, is1080P ? 1080 : 720);
            var oldsize    = game.RenderSize;
            var invalid    = false;
            var state      = new Rider();

            game.Track.Reset(state);
            var frame = flag.Frame;

            Recording      = true;
            Recording1080p = is1080P;
            game.Canvas.SetSize(game.RenderSize.Width, game.RenderSize.Height);
            game.Canvas.FindChildByName("buttons").Position(Pos.CenterH);

            if (frame > 400)                  //many frames, will likely lag the game. Update the window as a fallback.
            {
                if (frame > (20 * (60 * 40))) //too many frames, could lag the game very bad.
                {
                    return;
                }
                game.Title = Program.WindowTitle + " [Validating flag]";
                game.ProcessEvents();
            }
            for (var i = 0; i < frame; i++)
            {
                game.Track.Tick(state);
            }
            for (var i = 0; i < state.ModelAnchors.Length; i++)
            {
                if (state.ModelAnchors[i].Position != flag.State.ModelAnchors[i].Position ||
                    state.ModelAnchors[i].Prev != flag.State.ModelAnchors[i].Prev)
                {
                    invalid = true;
                    break;
                }
            }
            var frontbuffer = SafeFrameBuffer.GenFramebuffer();

            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, frontbuffer);

            var rbo2 = SafeFrameBuffer.GenRenderbuffer();

            SafeFrameBuffer.BindRenderbuffer(RenderbufferTarget.Renderbuffer, rbo2);
            SafeFrameBuffer.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Rgb8, resolution.Width, resolution.Height);
            SafeFrameBuffer.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, RenderbufferTarget.Renderbuffer, rbo2);

            SafeFrameBuffer.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
            if (!invalid)
            {
                string errormessage = "An unknown error occured during recording.";
                game.Title = Program.WindowTitle + " [Recording | Hold ESC to cancel]";
                game.ProcessEvents();
                var filename   = Program.CurrentDirectory + game.Track.Name + ".mp4";
                var flagbackup = flag;
                var hardexit   = false;
                game.Track.Flag();
                var recmodesave = game.SettingRecordingMode;
                game.SettingRecordingMode = true;
                game.Track.Start(true, true, false, false);
                game.Render();
                var dir = Program.CurrentDirectory + game.Track.Name + "_rec";
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                var firstframe = GrabScreenshot(game, frontbuffer);
                SaveScreenshot(game.RenderSize.Width, game.RenderSize.Height, firstframe, dir + Path.DirectorySeparatorChar + "tmp" + 0 + ".png");
                int[] savethreads = { 0 };
                for (var i = 0; i < frame; i++)
                {
                    if (hardexit)
                    {
                        break;
                    }
                    game.Track.Update(1);
                    game.Render();
                    var screenshot = GrabScreenshot(game, frontbuffer);
                    var objtopass  = new Tuple <byte[], int>(screenshot, i + 1);
                    savethreads[0] += 1;
                    var save = new Task(t =>
                    {
                        var passed = (Tuple <byte[], int>)t;
                        try
                        {
                            SaveScreenshot(game.RenderSize.Width, game.RenderSize.Height, passed.Item1, dir + Path.DirectorySeparatorChar + "tmp" + passed.Item2 + ".png");
                        }
                        catch
                        {
                            hardexit     = true;
                            errormessage = "An error occured when saving the frame.";
                        }
                        finally
                        {
                            Interlocked.Decrement(ref savethreads[0]);
                        }
                    }, objtopass);

                    save.Start();
                    if (Keyboard.GetState()[Key.Escape])
                    {
                        hardexit     = true;
                        errormessage = "The user manually cancelled recording.";
                    }
                    if (i % 40 == 0)
                    {
                        game.Title = string.Format("{0} [Recording {1:P}% | Hold ESC to cancel]", Program.WindowTitle, i / (double)frame);
                        game.ProcessEvents();
                    }
                }

                if (!hardexit)
                {
                    var parameters = new FFMPEGParameters();
                    parameters.AddOption("framerate", "40");
                    parameters.AddOption("i", "\"" + dir + Path.DirectorySeparatorChar + "tmp%d.png" + "\"");
                    parameters.AddOption("vf", "vflip");//we save images upside down expecting ffmpeg to flip more efficiently.
                    parameters.AddOption("c:v", "libx264");
                    parameters.AddOption("preset", "veryfast");
                    parameters.AddOption("qp", "0");

                    //    parameters.AddOption("scale",is1080p?"1920:1080":"1280:720");
                    parameters.OutputFilePath = filename;
                    var failed = false;
                    while (savethreads[0] != 0)
                    {
                        Thread.Sleep(1);
                    }
                    if (File.Exists(filename))
                    {
                        try
                        {
                            File.Delete(filename);
                        }
                        catch
                        {
                            Program.NonFatalError("A file with the name " + game.Track.Name + ".mp4 already exists");
                            failed       = true;
                            errormessage = "Cannot replace a file of the existing name " + game.Track.Name + ".mp4.";
                        }
                    }
                    if (!failed)
                    {
                        game.Title = Program.WindowTitle + " [Encoding Video | 0%]";
                        game.ProcessEvents();
                        try
                        {
                            FFMPEG.Execute(parameters, (string s) =>
                            {
                                int idx = s.IndexOf("frame=", StringComparison.InvariantCulture);
                                if (idx != -1)
                                {
                                    idx += "frame=".Length;
                                    for (; idx < s.Length; idx++)
                                    {
                                        if (char.IsNumber(s[idx]))
                                        {
                                            break;
                                        }
                                    }
                                    var space = s.IndexOf(" ", idx, StringComparison.InvariantCulture);
                                    if (space != -1)
                                    {
                                        var sub       = s.Substring(idx, space - idx);
                                        var parsedint = -1;
                                        if (int.TryParse(sub, out parsedint))
                                        {
                                            game.Title = Program.WindowTitle + string.Format(" [Encoding Video | {0:P}% | Hold ESC to cancel]", parsedint / (double)frame);
                                            game.ProcessEvents();
                                            if (Keyboard.GetState()[Key.Escape])
                                            {
                                                hardexit     = true;
                                                errormessage = "The user manually cancelled recording.";
                                                return(false);
                                            }
                                        }
                                    }
                                }
                                return(true);
                            });
                        }
                        catch (Exception e)
                        {
                            Program.NonFatalError("ffmpeg error.\r\n" + e);
                            hardexit     = true;
                            errormessage = "An ffmpeg error occured.";
                        }
                    }
                }
                try
                {
                    Directory.Delete(dir, true);
                }
                catch
                {
                    Program.NonFatalError("Unable to delete " + dir);
                }
                if (hardexit)
                {
                    try
                    {
                        File.Delete(filename);
                    }
                    catch
                    {
                        Program.NonFatalError("Unable to delete " + filename);
                    }
                }
                game.SettingRecordingMode = recmodesave;
                game.Title = Program.WindowTitle;
                game.Track.RestoreFlag(flagbackup);
                game.Track.Stop();
                game.ProcessEvents();
                var openwindows = game.Canvas.GetOpenWindows();
                foreach (var window in openwindows)
                {
                    var w = window as WindowControl;
                    w?.Close();
                }
                if (File.Exists(filename))
                {
                    try
                    {
                        AudioPlayback.Init();
                        MemoryStream ms = new MemoryStream(GameResources.beep);

                        SoundStream str = new SoundStream(ms);
                        str.Play(0, 1);
                        int count = 0;
                        while (str.Playing)
                        {
                            Thread.Sleep(1);
                            count += 1;
                            if (count >= 3000)//in case something weird happens
                            {
                                break;
                            }
                        }
                        str.Dispose();
                        ms.Dispose();
                    }
                    catch
                    {
                        //ignored
                    }
                }
                else
                {
                    PopupWindow.Error(game.Canvas, game, errormessage, "Error!");
                }
            }
            SafeFrameBuffer.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
            SafeFrameBuffer.DeleteFramebuffer(frontbuffer);
            SafeFrameBuffer.DeleteRenderbuffers(1, new[] { rbo2 });
            game.RenderSize = oldsize;
            Recording       = false;

            game.Canvas.SetSize(game.RenderSize.Width, game.RenderSize.Height);
            game.Canvas.FindChildByName("buttons").Position(Pos.CenterH);
        }