Example #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.lastBGChangeTime != lastBGChangeTime)
                    {
                        if (settings.BGImage == null)
                        {
                            if (bgTexID != -1)
                            {
                                GL.DeleteTexture(bgTexID);
                            }
                            bgTexID = -1;
                        }
                        else
                        {
                            if (bgTexID == -1)
                            {
                                bgTexID = GL.GenTexture();
                            }
                            try
                            {
                                loadImage(new Bitmap(settings.BGImage), bgTexID, false, true);
                            }
                            catch
                            {
                                MessageBox.Show("Couldn't load image");
                                if (bgTexID != -1)
                                {
                                    GL.DeleteTexture(bgTexID);
                                }
                                bgTexID = -1;
                            }
                        }
                        lastBGChangeTime = settings.lastBGChangeTime;
                    }

                    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 + "\n" + ex.StackTrace);
                            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;
                if (!settings.Paused)
                {
                    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;
                        }
                    }
                    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 (ffmpegvideo.HasExited || (settings.ffRenderMask && ffmpegmask.HasExited))
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("FFMPEG process closed unexpectedly!");
                        Console.WriteLine("Use 'ffmpeg debug' for more advanced info.");
                        Console.ResetColor();
                        settings.running = false;
                    }

                    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);
                    }
                }

                GLPostbuffer.UnbindBuffers();
                GL.Clear(ClearBufferMask.ColorBufferBit);
                GL.UseProgram(postShaderBlackFill);
                DrawScreenQuad();
                GL.UseProgram(postShader);
                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();
        }
Example #2
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);
            postShaderBlackFill = MakeShader(postShaderVert, postShaderFragBlackFill);

            uDownscaleRes = GL.GetUniformLocation(postShaderDownscale, "res");
            uDownscaleFac = GL.GetUniformLocation(postShaderDownscale, "factor");
        }