public ForwardPipeline(MasterRenderer renderer)
            : base(renderer)
        {
            GLError.Begin();

            forwardShader        = new WorldShader();
            shadowShader         = new ShadowShader();
            shadowMap            = new ShadowMap(GFXSettings.ShadowResolution, GFXSettings.ShadowResolution);
            shadowCamera         = new ShadowCamera();
            ppBuffer             = new PostProcessBuffer(ScreenWidth, ScreenHeight);
            ppShader             = new PostProcessShader();
            skyRenderTarg        = new TexRenderTarget(ScreenWidth, ScreenHeight);
            screenshotRenderTarg = new TexRenderTarget(1, 1);

            screenshotRenderTarg.Bind();
            GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
            screenshotRenderTarg.Unbind();

            ErrorCode err = GLError.End();

            if (err != ErrorCode.NoError)
            {
                throw new Exception(string.Format("Failed to initialize forward pipeline. OpenGL Error: {0}", err));
            }
        }
        public override void Render(float deltaTime)
        {
            TryBindScreenshotTarg();
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            if (IsRenderingEnabled(RendererFlags.Objects))
            {
                if (GFXSettings.RenderShadows)
                {
                    RenderShadowMap();
                    TryBindScreenshotTarg();
                }

                if (IsRenderingEnabled(RendererFlags.Sky))
                {
                    // Render the skybox
                    if (Renderer.FogEnabled && GFXSettings.FogQuality == FogQuality.High)
                    {
                        skyRenderTarg.Bind();

                        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
                        Renderer.Sky.Render(deltaTime, false);

                        skyRenderTarg.Unbind();
                    }
                }

                if (GFXSettings.EnablePostProcessing)
                {
                    ppBuffer.Bind();
                    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
                }

                if (IsRenderingEnabled(RendererFlags.Sky))
                {
                    Renderer.Sky.Render(deltaTime, true);
                }

                RenderObjects();

                if (GFXSettings.EnablePostProcessing)
                {
                    ppBuffer.Unbind();
                    TryBindScreenshotTarg();
                }

                // Tell the renderers to clear their batches
                foreach (Renderer3D renderer in Renderer.Renderer3Ds.Values)
                {
                    renderer.ClearBatch();
                }

                if (GFXSettings.EnablePostProcessing)
                {
                    Renderer.Gui.PrepareRender(ppShader);

                    GL.ActiveTexture(TextureUnit.Texture0);
                    ppBuffer.ColorTexture.Bind();

                    ppShader.LoadVector2("resolution", new Vector2(ScreenWidth, ScreenHeight));
                    ppShader.LoadMatrix4("transformationMatrix", Matrix4.Identity);
                    ppShader.LoadBool("apply_fxaa", GFXSettings.ApplyFXAA);

                    // Draw Post Process
                    GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);

                    ppBuffer.ColorTexture.Unbind();
                    Renderer.Gui.EndRender(ppShader);
                }
            }

            if (IsRenderingEnabled(RendererFlags.Gui2D))
            {
                StateManager.Enable(EnableCap.Blend);
                GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

                if (Renderer.DebugRenderShadowMap)
                {
                    Renderer.Gui.DebugRenderShadowMap(shadowMap);
                }

                StateManager.Disable(EnableCap.DepthTest);

                // Draw 2D UI
                foreach (Renderer2D renderer in Renderer.Renderer2Ds.Values)
                {
                    renderer.Prepare();
                    renderer.Render();
                }
            }

            if (screenshotRequest != null)
            {
                SaveCurrentBufferAsScreenshot();
                screenshotRenderTarg.Unbind();
                screenshotRequest = null;
            }
        }