示例#1
0
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            Task.Factory.StartNew(() => PlaybackLoop(), TaskCreationOptions.LongRunning);
            SpinWait.SpinUntil(() => playbackLoopStarted);
            Stopwatch watch = new Stopwatch();

            watch.Start();
            if (!settings.timeBasedNotes)
            {
                tempoFrameStep = ((double)midi.division / lastTempo) * (1000000.0 / settings.fps);
            }
            lock (render)
            {
                lastDeltaTimeOnScreen       = render.renderer.NoteScreenTime;
                render.renderer.CurrentMidi = midi.info;
            }
            int  noNoteFrames  = 0;
            long lastNC        = 0;
            bool firstRenderer = true;

            frameStartTime = DateTime.Now.Ticks;
            if (settings.timeBasedNotes)
            {
                microsecondsPerTick = 10000;
            }
            else
            {
                microsecondsPerTick = (long)((double)lastTempo / midi.division * 10);
            }
            while (settings.running && (noNoteFrames < settings.fps * 5 || midi.unendedTracks != 0))
            {
                if (!settings.Paused || settings.forceReRender)
                {
                    if (settings.lastyBGChangeTime != lastBGChangeTime)
                    {
                        if (settings.BGImage == null)
                        {
                            if (bgTexID != -1)
                            {
                                GL.DeleteTexture(bgTexID);
                            }
                            bgTexID = -1;
                        }
                        else
                        {
                            if (bgTexID == -1)
                            {
                                bgTexID = GL.GenTexture();
                            }
                            loadImage(settings.BGImage, bgTexID, false, true);
                        }
                    }

                    lock (render)
                    {
                        try
                        {
                            if (render.disposeQueue.Count != 0)
                            {
                                try
                                {
                                    while (true)
                                    {
                                        var r = render.disposeQueue.Dequeue();
                                        if (r.Initialized)
                                        {
                                            try
                                            {
                                                r.Dispose();
                                            }
                                            catch { }
                                            GC.Collect();
                                        }
                                    }
                                }
                                catch (InvalidOperationException) { }
                            }
                            if (!render.renderer.Initialized)
                            {
                                render.renderer.Init();
                                render.renderer.NoteColors = midi.tracks.Select(t => t.trkColors).ToArray();
                                render.renderer.ReloadTrackColors();
                                if (firstRenderer)
                                {
                                    firstRenderer = false;
                                    midi.SetZeroColors();
                                }
                                render.renderer.CurrentMidi = midi.info;
                                lock (globalDisplayNotes)
                                {
                                    foreach (Note n in globalDisplayNotes)
                                    {
                                        n.meta = null;
                                    }
                                }
                            }
                            render.renderer.Tempo = 60000000.0 / lastTempo;
                            lastDeltaTimeOnScreen = render.renderer.NoteScreenTime;
                            if (settings.timeBasedNotes)
                            {
                                SpinWait.SpinUntil(() => (midi.currentFlexSyncTime > midiTime + lastDeltaTimeOnScreen + tempoFrameStep * settings.tempoMultiplier || midi.unendedTracks == 0) || !settings.running);
                            }
                            else
                            {
                                SpinWait.SpinUntil(() => (midi.currentSyncTime > midiTime + lastDeltaTimeOnScreen + tempoFrameStep * settings.tempoMultiplier || midi.unendedTracks == 0) || !settings.running);
                            }
                            if (!settings.running)
                            {
                                break;
                            }

                            render.renderer.RenderFrame(globalDisplayNotes, midiTime, finalCompositeBuff.BufferID);
                            lastNC = render.renderer.LastNoteCount;
                            if (lastNC == 0 && midi.unendedTracks == 0)
                            {
                                noNoteFrames++;
                            }
                            else
                            {
                                noNoteFrames = 0;
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("The renderer has crashed\n" + ex.Message);
                            break;
                        }
                    }
                }
                double mv = 1;
                if (settings.realtimePlayback)
                {
                    mv = (DateTime.Now.Ticks - frameStartTime) / microsecondsPerTick / tempoFrameStep;
                    if (mv > settings.fps / 4)
                    {
                        mv = settings.fps / 4;
                    }
                }
                lastMV = mv;
                lock (globalTempoEvents)
                {
                    while (globalTempoEvents.First != null && midiTime + (tempoFrameStep * mv * settings.tempoMultiplier) > globalTempoEvents.First.pos)
                    {
                        var t = globalTempoEvents.Pop();
                        if (t.tempo == 0)
                        {
                            Console.WriteLine("Zero tempo event encountered, ignoring");
                            continue;
                        }
                        var _t = ((t.pos) - midiTime) / (tempoFrameStep * mv * settings.tempoMultiplier);
                        mv *= 1 - _t;
                        if (!settings.timeBasedNotes)
                        {
                            tempoFrameStep = ((double)midi.division / t.tempo) * (1000000.0 / settings.fps);
                        }
                        lastTempo = t.tempo;
                        midiTime  = t.pos;
                    }
                }
                if (!settings.Paused)
                {
                    midiTime += mv * tempoFrameStep * settings.tempoMultiplier;
                }
                frameStartTime = DateTime.Now.Ticks;
                if (settings.timeBasedNotes)
                {
                    microsecondsPerTick = 10000;
                }
                else
                {
                    microsecondsPerTick = (long)(lastTempo / midi.division * 10);
                }

                while (globalColorEvents.First != null && globalColorEvents.First.pos < midiTime)
                {
                    var c     = globalColorEvents.Pop();
                    var track = c.track;
                    if (!settings.ignoreColorEvents)
                    {
                        if (c.channel == 0x7F)
                        {
                            for (int i = 0; i < 16; i++)
                            {
                                c.track.trkColors[i].left      = c.col1;
                                c.track.trkColors[i].right     = c.col2;
                                c.track.trkColors[i].isDefault = false;
                            }
                        }
                        else
                        {
                            c.track.trkColors[c.channel].left      = c.col1;
                            c.track.trkColors[c.channel].right     = c.col2;
                            c.track.trkColors[c.channel].isDefault = false;
                        }
                    }
                }

                downscaleBuff.BindBuffer();
                GL.Clear(ClearBufferMask.ColorBufferBit);
                GL.Viewport(0, 0, settings.width / settings.downscale, settings.height / settings.downscale);
                if (bgTexID != -1)
                {
                    GL.UseProgram(postShaderFlip);
                    GL.BindTexture(TextureTarget.Texture2D, bgTexID);
                    DrawScreenQuad();
                }

                if (settings.downscale > 1)
                {
                    GL.UseProgram(postShaderDownscale);
                    GL.Uniform1(uDownscaleFac, (int)settings.downscale);
                    GL.Uniform2(uDownscaleRes, new Vector2(settings.width / settings.downscale, settings.height / settings.downscale));
                }
                else
                {
                    GL.UseProgram(postShader);
                }

                finalCompositeBuff.BindTexture();
                DrawScreenQuad();

                if (settings.ffRender)
                {
                    if (!settings.ffRenderMask)
                    {
                        GL.UseProgram(postShader);
                    }
                    else
                    {
                        GL.UseProgram(postShaderMaskColor);
                    }
                    finalCompositeBuff.BindTexture();
                    ffmpegOutputBuff.BindBuffer();
                    GL.Clear(ClearBufferMask.ColorBufferBit);
                    GL.Viewport(0, 0, settings.width / settings.downscale, settings.height / settings.downscale);
                    downscaleBuff.BindTexture();
                    DrawScreenQuad();
                    IntPtr unmanagedPointer = Marshal.AllocHGlobal(pixels.Length);
                    GL.ReadPixels(0, 0, settings.width / settings.downscale, settings.height / settings.downscale, PixelFormat.Bgra, PixelType.UnsignedByte, unmanagedPointer);
                    Marshal.Copy(unmanagedPointer, pixels, 0, pixels.Length);

                    if (lastRenderPush != null)
                    {
                        lastRenderPush.GetAwaiter().GetResult();
                    }
                    lastRenderPush = Task.Run(() =>
                    {
                        ffmpegvideo.StandardInput.BaseStream.Write(pixels, 0, pixels.Length);
                    });
                    Marshal.FreeHGlobal(unmanagedPointer);

                    if (settings.ffRenderMask)
                    {
                        if (lastRenderPushMask != null)
                        {
                            lastRenderPushMask.GetAwaiter().GetResult();
                        }
                        GL.UseProgram(postShaderMask);
                        ffmpegOutputBuff.BindBuffer();
                        GL.Clear(ClearBufferMask.ColorBufferBit);
                        GL.Viewport(0, 0, settings.width / settings.downscale, settings.height / settings.downscale);
                        downscaleBuff.BindTexture();
                        DrawScreenQuad();
                        unmanagedPointer = Marshal.AllocHGlobal(pixelsmask.Length);
                        GL.ReadPixels(0, 0, settings.width / settings.downscale, settings.height / settings.downscale, PixelFormat.Bgra, PixelType.UnsignedByte, unmanagedPointer);
                        Marshal.Copy(unmanagedPointer, pixelsmask, 0, pixelsmask.Length);

                        if (lastRenderPush != null)
                        {
                            lastRenderPush.GetAwaiter().GetResult();
                        }
                        lastRenderPush = Task.Run(() =>
                        {
                            ffmpegmask.StandardInput.BaseStream.Write(pixelsmask, 0, pixelsmask.Length);
                        });
                        Marshal.FreeHGlobal(unmanagedPointer);
                    }
                }

                GL.UseProgram(postShader);
                GLPostbuffer.UnbindBuffers();
                GL.Clear(ClearBufferMask.ColorBufferBit);
                GL.Viewport(0, 0, Width, Height);
                downscaleBuff.BindTexture();
                DrawScreenQuad();
                GLPostbuffer.UnbindTextures();
                if (settings.ffRender)
                {
                    VSync = VSyncMode.Off;
                }
                else if (settings.vsync)
                {
                    VSync = VSyncMode.On;
                }
                else
                {
                    VSync = VSyncMode.Off;
                }
                try
                {
                    SwapBuffers();
                }
                catch
                {
                    break;
                }
                ProcessEvents();
                double fr = 10000000.0 / watch.ElapsedTicks;
                settings.liveFps = (settings.liveFps * 2 + fr) / 3;
                watch.Reset();
                watch.Start();
            }
            Console.WriteLine("Left render loop");
            settings.running = false;
            if (settings.ffRender)
            {
                if (lastRenderPush != null)
                {
                    lastRenderPush.GetAwaiter().GetResult();
                }
                ffmpegvideo.StandardInput.Close();
                ffmpegvideo.Close();
                if (settings.ffRenderMask)
                {
                    if (lastRenderPushMask != null)
                    {
                        lastRenderPushMask.GetAwaiter().GetResult();
                    }
                    ffmpegmask.StandardInput.Close();
                    ffmpegmask.Close();
                }
            }
            Console.WriteLine("Disposing current renderer");
            try
            {
                render.renderer.Dispose();
            }
            catch { }
            try
            {
                Console.WriteLine("Disposing of other renderers");
                while (render.disposeQueue.Count != 0)
                {
                    var r = render.disposeQueue.Dequeue();
                    try
                    {
                        if (r.Initialized)
                        {
                            r.Dispose();
                        }
                    }
                    catch { }
                }
            }
            catch (InvalidOperationException) { }
            Console.WriteLine("Disposed of renderers");

            globalDisplayNotes = null;
            globalTempoEvents  = null;
            globalColorEvents  = null;
            pixels             = null;
            pixelsmask         = null;
            if (settings.ffRender)
            {
                ffmpegvideo.Dispose();
                if (settings.ffRenderMask)
                {
                    ffmpegmask.Dispose();
                }
            }
            ffmpegvideo = null;
            ffmpegmask  = null;


            finalCompositeBuff.Dispose();
            ffmpegOutputBuff.Dispose();
            downscaleBuff.Dispose();
            finalCompositeBuff = null;
            ffmpegOutputBuff   = null;
            downscaleBuff      = null;

            GL.DeleteBuffers(2, new int[] { screenQuadBuffer, screenQuadIndexBuffer });

            GL.DeleteProgram(postShader);
            GL.DeleteProgram(postShaderMask);
            GL.DeleteProgram(postShaderMaskColor);
            GL.DeleteProgram(postShaderDownscale);

            midi   = null;
            render = null;
            Console.WriteLine("Closing window");

            this.Close();
        }
示例#2
0
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            Stopwatch watch = new Stopwatch();

            watch.Start();
            tempoFrameStep = ((double)midi.division / lastTempo) * (1000000 / settings.fps);
            lock (render)
            {
                lastDeltaTimeOnScreen = render.renderer.NoteScreenTime;
            }
            int  noNoteFrames = 0;
            long lastNC       = 0;

            while (settings.running && noNoteFrames < settings.fps * 5 || midi.unendedTracks != 0)
            {
                if (!settings.paused || settings.forceReRender)
                {
                    lock (render)
                    {
                        try
                        {
                            if (render.disposeQueue.Count != 0)
                            {
                                try
                                {
                                    while (true)
                                    {
                                        var r = render.disposeQueue.Dequeue();
                                        if (r.Initialized)
                                        {
                                            r.Dispose();
                                        }
                                    }
                                }
                                catch (InvalidOperationException) { }
                            }
                            if (!render.renderer.Initialized)
                            {
                                render.renderer.Init();
                                List <Color4[]> trkcolors = new List <Color4[]>();
                                foreach (var t in midi.tracks)
                                {
                                    trkcolors.Add(t.trkColor);
                                }
                                render.renderer.SetTrackColors(trkcolors.ToArray());
                                lock (globalDisplayNotes)
                                {
                                    foreach (Note n in globalDisplayNotes)
                                    {
                                        n.meta = null;
                                    }
                                }
                            }
                            render.renderer.LastMidiTimePerTick = lastTempo / midi.division;
                            lastDeltaTimeOnScreen = render.renderer.NoteScreenTime;
                            SpinWait.SpinUntil(() => midi.currentSyncTime > midiTime + lastDeltaTimeOnScreen + tempoFrameStep || midi.unendedTracks == 0 || !settings.running);
                            if (!settings.running)
                            {
                                break;
                            }

                            render.renderer.RenderFrame(globalDisplayNotes, midiTime, finalCompositeBuff.BufferID);
                            lastNC = render.renderer.LastNoteCount;
                            RenderAllText(lastNC);
                            if (lastNC == 0 && midi.unendedTracks == 0)
                            {
                                noNoteFrames++;
                            }
                            else
                            {
                                noNoteFrames = 0;
                            }
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show("The renderer has crashed\n" + ex.Message);
                            break;
                        }
                    }
                }
                double mv = 1;
                lock (globalTempoEvents)
                {
                    while (globalTempoEvents.First != null && midiTime + (tempoFrameStep * mv * settings.tempoMultiplier) > globalTempoEvents.First.pos)
                    {
                        var t  = globalTempoEvents.Pop();
                        var _t = ((t.pos) - midiTime) / (tempoFrameStep * mv * settings.tempoMultiplier);
                        mv            *= 1 - _t;
                        tempoFrameStep = ((double)midi.division / t.tempo) * (1000000.0 / settings.fps);
                        lastTempo      = t.tempo;
                        midiTime       = t.pos;
                    }
                }
                if (!settings.paused)
                {
                    midiTime += mv * tempoFrameStep * settings.tempoMultiplier;
                }

                while (globalColorEvents.First != null && globalColorEvents.First.pos < midiTime)
                {
                    var c     = globalColorEvents.Pop();
                    var track = c.track;
                    if (c.channel == 0x7F)
                    {
                        for (int i = 0; i < 16; i++)
                        {
                            c.track.trkColor[i * 2]     = c.col1;
                            c.track.trkColor[i * 2 + 1] = c.col2;
                        }
                    }
                    else
                    {
                        c.track.trkColor[c.channel * 2]     = c.col1;
                        c.track.trkColor[c.channel * 2 + 1] = c.col2;
                    }
                }

                if (settings.ffRender)
                {
                    finalCompositeBuff.BindBuffer();
                    IntPtr unmanagedPointer = Marshal.AllocHGlobal(pixels.Length);
                    GL.ReadPixels(0, 0, settings.width, settings.height, PixelFormat.Rgb, PixelType.UnsignedByte, unmanagedPointer);
                    Marshal.Copy(unmanagedPointer, pixels, 0, pixels.Length);
                    if (lastRenderPush != null)
                    {
                        lastRenderPush.GetAwaiter().GetResult();
                    }
                    lastRenderPush = Task.Run(() => ffmpeg.StandardInput.BaseStream.Write(pixels, 0, pixels.Length));
                    Marshal.FreeHGlobal(unmanagedPointer);
                }
                if (settings.imgRender)
                {
                    finalCompositeBuff.BindBuffer();
                    IntPtr unmanagedPointer = Marshal.AllocHGlobal(pixels.Length);
                    GL.ReadPixels(0, 0, settings.width, settings.height, PixelFormat.Bgra, PixelType.UnsignedByte, unmanagedPointer);
                    if (lastRenderPush != null)
                    {
                        lastRenderPush.GetAwaiter().GetResult();
                    }
                    lastRenderPush = Task.Run(() =>
                    {
                        Bitmap output = new Bitmap(settings.width, settings.height, settings.width * 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, unmanagedPointer);
                        output.RotateFlip(RotateFlipType.RotateNoneFlipY);
                        output.Save(settings.imgPath + "\\img_" + imgnumber++ + ".png");
                        output.Dispose();
                        Marshal.FreeHGlobal(unmanagedPointer);
                    });
                }

                GL.UseProgram(postShader);
                GLPostbuffer.UnbindBuffers();
                GL.Clear(ClearBufferMask.ColorBufferBit);
                GL.Viewport(0, 0, Width, Height);
                finalCompositeBuff.BindTexture();
                DrawScreenQuad();
                GLPostbuffer.UnbindTextures();
                if (settings.ffRender)
                {
                    VSync = VSyncMode.Off;
                }
                else if (settings.vsync)
                {
                    VSync = VSyncMode.On;
                }
                else
                {
                    VSync = VSyncMode.Off;
                }
                try
                {
                    SwapBuffers();
                }
                catch
                {
                    break;
                }
                ProcessEvents();
                double fr = 10000000.0 / watch.ElapsedTicks;
                settings.liveFps = (settings.liveFps * 2 + fr) / 3;
                watch.Reset();
                watch.Start();
            }
            settings.running = false;
            if (settings.ffRender)
            {
                if (lastRenderPush != null)
                {
                    lastRenderPush.GetAwaiter().GetResult();
                }
                ffmpeg.StandardInput.Close();
                ffmpeg.Close();
            }
            try
            {
                while (true)
                {
                    var r = render.disposeQueue.Dequeue();
                    if (!r.Initialized)
                    {
                        r.Dispose();
                    }
                }
            }
            catch (InvalidOperationException) { }
            render.renderer.Dispose();
            this.Close();
        }
示例#3
0
        public RenderWindow(CurrentRendererPointer renderer, MidiFile midi, RenderSettings settings) : base(16, 9, new GraphicsMode(new ColorFormat(8, 8, 8, 8)), "Render", GameWindowFlags.Default, DisplayDevice.Default)
        {
            Width    = (int)(DisplayDevice.Default.Width / 1.5);
            Height   = (int)((double)Width / settings.width * settings.height);
            Location = new Point((DisplayDevice.Default.Width - Width) / 2, (DisplayDevice.Default.Height - Height) / 2);
            //textEngine = new GLTextEngine();
            render        = renderer;
            this.settings = settings;
            lastTempo     = midi.zerothTempo;
            lock (render)
            {
                render.renderer.Tempo = 60000000.0 / midi.zerothTempo;
                midiTime = -render.renderer.NoteScreenTime;
                if (settings.timeBasedNotes)
                {
                    tempoFrameStep = 1000.0 / settings.fps;
                }
                else
                {
                    tempoFrameStep = ((double)midi.division / lastTempo) * (1000000 / settings.fps);
                }
                midiTime -= tempoFrameStep * settings.renderSecondsDelay * settings.fps;
            }

            globalDisplayNotes   = midi.globalDisplayNotes;
            globalTempoEvents    = midi.globalTempoEvents;
            globalColorEvents    = midi.globalColorEvents;
            globalPlaybackEvents = midi.globalPlaybackEvents;
            this.midi            = midi;
            if (settings.ffRender)
            {
                pixels      = new byte[settings.width * settings.height * 4 / settings.downscale / settings.downscale];
                ffmpegvideo = startNewFF(settings.ffPath);
                if (settings.ffRenderMask)
                {
                    pixelsmask = new byte[settings.width * settings.height * 4 / settings.downscale / settings.downscale];
                    ffmpegmask = startNewFF(settings.ffMaskPath);
                }
            }

            finalCompositeBuff = new GLPostbuffer(settings.width, settings.height);
            ffmpegOutputBuff   = new GLPostbuffer(settings.width / settings.downscale, settings.height / settings.downscale);
            downscaleBuff      = new GLPostbuffer(settings.width / settings.downscale, settings.height / settings.downscale);

            GL.GenBuffers(1, out screenQuadBuffer);
            GL.GenBuffers(1, out screenQuadIndexBuffer);

            GL.BindBuffer(BufferTarget.ArrayBuffer, screenQuadBuffer);
            GL.BufferData(
                BufferTarget.ArrayBuffer,
                (IntPtr)(screenQuadArray.Length * 8),
                screenQuadArray,
                BufferUsageHint.StaticDraw);

            GL.BindBuffer(BufferTarget.ElementArrayBuffer, screenQuadIndexBuffer);
            GL.BufferData(
                BufferTarget.ElementArrayBuffer,
                (IntPtr)(screenQuadArrayIndex.Length * 4),
                screenQuadArrayIndex,
                BufferUsageHint.StaticDraw);

            postShader          = MakeShader(postShaderVert, postShaderFrag);
            postShaderFlip      = MakeShader(postShaderFlipVert, postShaderFrag);
            postShaderMask      = MakeShader(postShaderVert, postShaderFragAlphaMask);
            postShaderMaskColor = MakeShader(postShaderVert, postShaderFragAlphaMaskColor);
            postShaderDownscale = MakeShader(postShaderVert, postShaderFragDownscale);

            uDownscaleRes = GL.GetUniformLocation(postShaderDownscale, "res");
            uDownscaleFac = GL.GetUniformLocation(postShaderDownscale, "factor");
        }
示例#4
0
        public RenderWindow(CurrentRendererPointer renderer, MidiFile midi, RenderSettings settings) : base(16, 9, new GraphicsMode(new ColorFormat(8, 8, 8, 8)), "Render", GameWindowFlags.Default, DisplayDevice.Default)
        {
            Width         = (int)(DisplayDevice.Default.Width / 1.5);
            Height        = (int)((double)Width / settings.width * settings.height);
            Location      = new Point((DisplayDevice.Default.Width - Width) / 2, (DisplayDevice.Default.Height - Height) / 2);
            textEngine    = new GLTextEngine();
            render        = renderer;
            this.settings = settings;
            lastTempo     = midi.zerothTempo;
            lock (render)
            {
                render.renderer.LastMidiTimePerTick = (double)midi.zerothTempo / midi.division;
                midiTime       = -render.renderer.NoteScreenTime;
                tempoFrameStep = ((double)midi.division / lastTempo) * (1000000 / settings.fps);
                midiTime      -= tempoFrameStep * settings.renderSecondsDelay * settings.fps;
            }
            pixels = new byte[settings.width * settings.height * 3];

            //WindowBorder = WindowBorder.Hidden;
            globalDisplayNotes = midi.globalDisplayNotes;
            globalTempoEvents  = midi.globalTempoEvents;
            globalColorEvents  = midi.globalColorEvents;
            this.midi          = midi;
            if (settings.ffRender)
            {
                string args = "-hide_banner";
                if (settings.includeAudio)
                {
                    double fstep  = ((double)midi.division / lastTempo) * (1000000 / settings.fps);
                    double offset = -midiTime / fstep / settings.fps;
                    args = "" +
                           " -f rawvideo -s " + settings.width + "x" + settings.height +
                           " -pix_fmt rgb24 -r " + settings.fps + " -i -" +
                           " -itsoffset " + offset + " -i \"" + settings.audioPath + "\"" +
                           " -vf vflip -vcodec libx264 -pix_fmt yuv420p -acodec aac";
                }
                else
                {
                    args = "" +
                           " -f rawvideo -s " + settings.width + "x" + settings.height +
                           " -strict -2" +
                           " -pix_fmt rgb24 -r " + settings.fps + " -i -" +
                           " -vf vflip -vcodec libx264 -pix_fmt yuv420p";
                }
                if (settings.useBitrate)
                {
                    args += " -b:v " + settings.bitrate + "k" +
                            " -maxrate " + settings.bitrate + "k" +
                            " -minrate " + settings.bitrate + "k";
                }
                else
                {
                    args += " -preset " + settings.crfPreset + " -crf " + settings.crf;
                }
                args            += " -y \"" + settings.ffPath + "\"";
                ffmpeg.StartInfo = new ProcessStartInfo("ffmpeg", args);
                ffmpeg.StartInfo.RedirectStandardInput = true;
                ffmpeg.StartInfo.UseShellExecute       = false;
                ffmpeg.StartInfo.RedirectStandardError = true;
                try
                {
                    ffmpeg.Start();
                    Console.OpenStandardOutput();
                    Regex messageMatch = new Regex("\\[.*@.*\\]");
                    ffmpeg.ErrorDataReceived += (s, e) =>
                    {
                        if (e.Data == null)
                        {
                            return;
                        }
                        if (e.Data.Contains("frame="))
                        {
                            Console.Write(e.Data);
                            Console.SetCursorPosition(0, Console.CursorTop);
                        }
                        if (e.Data.Contains("Conversion failed!"))
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("An error occured in FFMPEG, closing!");
                            Console.ResetColor();
                            settings.running = false;
                        }
                        if (messageMatch.IsMatch(e.Data))
                        {
                            Console.WriteLine(e.Data);
                        }
                    };
                    ffmpeg.BeginErrorReadLine();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("There was an error starting the ffmpeg process\nNo video will be written\n(Is ffmpeg.exe in the same folder as this program?)\n\n\"" + ex.Message + "\"");
                    settings.ffRender = false;
                }
            }
            else if (settings.imgRender)
            {
                if (!Directory.Exists(settings.imgPath))
                {
                    Directory.CreateDirectory(settings.imgPath);
                }
            }
            else
            {
                if (!settings.vsync)
                {
                    VSync = VSyncMode.Off;
                }
            }

            finalCompositeBuff = new GLPostbuffer(settings);

            GL.GenBuffers(1, out screenQuadBuffer);
            GL.GenBuffers(1, out screenQuadIndexBuffer);

            GL.BindBuffer(BufferTarget.ArrayBuffer, screenQuadBuffer);
            GL.BufferData(
                BufferTarget.ArrayBuffer,
                (IntPtr)(screenQuadArray.Length * 8),
                screenQuadArray,
                BufferUsageHint.StaticDraw);

            GL.BindBuffer(BufferTarget.ElementArrayBuffer, screenQuadIndexBuffer);
            GL.BufferData(
                BufferTarget.ElementArrayBuffer,
                (IntPtr)(screenQuadArrayIndex.Length * 4),
                screenQuadArrayIndex,
                BufferUsageHint.StaticDraw);

            postShader = MakeShader(postShaderVert, postShaderFrag);
        }