public override void Draw(RendererBase <ToyWorld> renderer, ToyWorld world)
        {
            if (Settings.EnabledEffects == RenderRequestEffect.None)
            {
                return;
            }

            GL.Enable(EnableCap.Blend);
            GL.Enable(EnableCap.DepthTest);
            GL.DepthMask(false);

            Owner.FrontFbo.Bind();

            const float effectHeight = 1.5f;

            if (Settings.EnabledEffects.HasFlag(RenderRequestEffect.Lights))
            {
                //GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.SrcAlpha); // Fades non-lit stuff to black
                GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.DstAlpha);

                renderer.EffectManager.Use(m_pointLightEffect);

                foreach (var character in world.Atlas.Characters)
                {
                    m_pointLightEffect.ColorUniform(new Vector4(0.85f));
                    float lightDecay = character.ForwardSpeed;
                    m_pointLightEffect.IntensityDecayUniform(new Vector2(1, lightDecay));
                    m_pointLightEffect.LightPosUniform(new Vector3(character.Position, effectHeight));

                    // Set up transformation to world and screen space for noise effect
                    Matrix mw = Matrix.Identity;
                    // Model transform -- scale from (-1,1) to viewSize/2, center on origin
                    const float minIntensity   = 0.01f;
                    const float intensityScale = (1 / minIntensity - 1) / 30;
                    mw *= Matrix.CreateScale(intensityScale / lightDecay / 2);
                    // World transform -- move center to view center
                    mw *= Matrix.CreateTranslation(new Vector3(character.Position, effectHeight));
                    m_pointLightEffect.ModelWorldUniform(ref mw);
                    Matrix mvp = mw * Owner.ViewProjectionMatrix;
                    m_pointLightEffect.ModelViewProjectionUniform(ref mvp);

                    Owner.Quad.Draw();
                }

                Owner.SetDefaultBlending();
            }

            if (Settings.EnabledEffects.HasFlag(RenderRequestEffect.Smoke))
            {
                renderer.EffectManager.Use(m_smokeEffect);

                // Set up transformation to world and screen space for noise effect
                Matrix mw = Matrix.Identity;
                // Model transform -- scale from (-1,1) to viewSize/2, center on origin
                mw *= Matrix.CreateScale(Owner.ViewV.Size / 2);
                // World transform -- move center to view center
                mw *= Matrix.CreateTranslation(new Vector3(Owner.ViewV.Center, effectHeight + 0.05f));
                // View and projection transforms
                Matrix mvp = mw * Owner.ViewProjectionMatrix;

                m_smokeEffect.ModelWorldUniform(ref mw);
                m_smokeEffect.ModelViewProjectionUniform(ref mvp);

                m_smokeEffect.AmbientDiffuseTermsUniform(new Vector2(AmbientTerm, GetGlobalDiffuseComponent(world)));

                // Advance noise time by a visually pleasing step; wrap around if we run for waaaaay too long.
                double step = 0.005d * Settings.SmokeTransformationSpeedCoefficient;
                double seed = renderer.SimTime * step % 3e6d;
                m_smokeEffect.TimeStepUniform(new Vector2((float)seed, (float)step));
                m_smokeEffect.MeanScaleUniform(new Vector2(Settings.SmokeIntensityCoefficient, Settings.SmokeScaleCoefficient));

                Owner.Quad.Draw();
            }

            // more stufffs
        }