コード例 #1
0
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                IShader shader = needsRoundedShader ? RoundedTextureShader : TextureShader;

                shader.Bind();

                var   avgColour   = (Color4)DrawColourInfo.Colour.AverageColour;
                float shadowAlpha = (float)Math.Pow(Math.Max(Math.Max(avgColour.R, avgColour.G), avgColour.B), 2);

                //adjust shadow alpha based on highest component intensity to avoid muddy display of darker text.
                //squared result for quadratic fall-off seems to give the best result.
                var shadowColour = DrawColourInfo.Colour;

                shadowColour.ApplyChild(ShadowColour.MultiplyAlpha(shadowAlpha));

                for (int i = 0; i < Parts.Count; i++)
                {
                    if (Shadow)
                    {
                        var shadowQuad = Parts[i].DrawQuad;
                        shadowQuad.TopLeft     += ShadowOffset;
                        shadowQuad.TopRight    += ShadowOffset;
                        shadowQuad.BottomLeft  += ShadowOffset;
                        shadowQuad.BottomRight += ShadowOffset;

                        Parts[i].Texture.DrawQuad(shadowQuad, shadowColour, vertexAction: vertexAction);
                    }

                    Parts[i].Texture.DrawQuad(Parts[i].DrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
                }

                shader.Unbind();
            }
コード例 #2
0
        public void Draw(DrawState state)
        {
            state.PushWorldTranslateMultiply(ref this.position);

            if (geometry.CullTest(state))
            {
                //draw the geometry
                shader.Bind(state);
                geometry.Draw(state);

                //now, if set, draw the wireframe too
                if (wireframeShader != null)
                {
                    wireframeShader.Bind(state);

                    //show the wireframe, disabling depth testing
                    state.PushRenderState();
                    state.RenderState.DepthColourCull.DepthTestEnabled = false;
                    //also set additive blending
                    state.RenderState.AlphaBlend = AlphaBlendState.Additive;
                    //set wireframe
                    state.RenderState.DepthColourCull.FillMode = FillMode.WireFrame;

                    //draw
                    geometry.Draw(state);

                    state.PopRenderState();
                }
            }

            state.PopWorldMatrix();
        }
コード例 #3
0
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                if (texture?.Available != true || segments.Count == 0)
                {
                    return;
                }

                GLWrapper.PushDepthInfo(DepthInfo.Default);

                // Blending is removed to allow for correct blending between the wedges of the path.
                GLWrapper.SetBlend(BlendingParameters.None);

                pathShader.Bind();

                texture.TextureGL.WrapMode = TextureWrapMode.ClampToEdge;
                texture.TextureGL.Bind();

                updateVertexBuffer();

                pathShader.Unbind();

                GLWrapper.PopDepthInfo();
            }
コード例 #4
0
ファイル: CursorTrail.cs プロジェクト: Tiller431/yes
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                shader.Bind();
                shader.GetUniform <float>("g_FadeClock").UpdateValue(ref time);

                for (int i = 0; i < parts.Length; ++i)
                {
                    Vector2 pos       = parts[i].Position;
                    float   localTime = parts[i].Time;

                    DrawQuad(
                        texture,
                        new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
                        DrawColourInfo.Colour,
                        null,
                        v => vertexBatch.Add(new TexturedTrailVertex
                    {
                        Position        = v.Position,
                        TexturePosition = v.TexturePosition,
                        Time            = localTime + 1,
                        Colour          = v.Colour,
                    }));
                }

                shader.Unbind();
            }
コード例 #5
0
 /// <summary></summary>
 /// <param name="state"></param>
 /// <param name="maskOnly"></param>
 protected override void BindShader(DrawState state, bool maskOnly)
 {
     if (shader == null)
     {
         throw new InvalidOperationException("Shader == null");
     }
     shader.Bind(state);
 }
コード例 #6
0
ファイル: Shaders.cs プロジェクト: OwenMcDonnell/MonoAGS
        private static void setVignetteResolution()
        {
            var resolution = AGSGame.Game.Settings.WindowSize;

            _vignetteShader.Compile();
            _vignetteShader.Bind();
            _vignetteShader.SetVariable("resolution", resolution.Width, resolution.Height);
        }
コード例 #7
0
ファイル: CursorTrail.cs プロジェクト: vuduclong0309/osu
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                shader.GetUniform <float>("g_FadeClock").UpdateValue(ref time);

                int updateStart = -1, updateEnd = 0;

                for (int i = 0; i < parts.Length; ++i)
                {
                    if (parts[i].WasUpdated)
                    {
                        if (updateStart == -1)
                        {
                            updateStart = i;
                        }
                        updateEnd = i + 1;

                        int start = i * 4;
                        int end   = start;

                        Vector2 pos       = parts[i].Position;
                        float   localTime = parts[i].Time;

                        texture.DrawQuad(
                            new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
                            DrawColourInfo.Colour,
                            null,
                            v => vertexBuffer.Vertices[end++] = new TexturedTrailVertex
                        {
                            Position        = v.Position,
                            TexturePosition = v.TexturePosition,
                            Time            = localTime + 1,
                            Colour          = v.Colour,
                        });

                        parts[i].WasUpdated = false;
                    }
                    else if (updateStart != -1)
                    {
                        vertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4);
                        updateStart = -1;
                    }
                }

                // Update all remaining vertices that have been changed.
                if (updateStart != -1)
                {
                    vertexBuffer.UpdateRange(updateStart * 4, updateEnd * 4);
                }

                base.Draw(vertexAction);

                shader.Bind();

                texture.TextureGL.Bind();
                vertexBuffer.Draw();

                shader.Unbind();
            }
コード例 #8
0
        /// <summary>
        /// Submit something to be drawn
        /// </summary>
        /// <param name="shader"></param>
        /// <param name="vertexArray"></param>
        /// <param name="transform"></param>
        public static void Submit(IShader shader, IVertexArray vertexArray, Matrix4x4 transform)
        {
            shader.Bind();
            shader.SetMat4("u_ViewProjection", sceneData.ViewProjectionMatrix);
            shader.SetMat4("u_Transform", transform);

            vertexArray.Bind();
            RenderingAPI.DrawIndexed(vertexArray);
        }
コード例 #9
0
ファイル: 2DRenderer.cs プロジェクト: ejrich/Pretend
        public void Submit(IShader shader, IVertexArray vertexArray)
        {
            shader.Bind();
            shader.SetMat4("viewProjection", _viewProjection);

            vertexArray.Bind();

            _renderContext.Draw(vertexArray);
        }
コード例 #10
0
 private static IShader applyObjectShader(IShader shader)
 {
     if (shader != null)
     {
         shader = shader.Compile();
     }
     shader?.Bind();
     return(shader);
 }
コード例 #11
0
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                shader.Bind();

                Vector2 inflation = DrawInfo.MatrixInverse.ExtractScale().Xy;

                ColourInfo colourInfo = DrawColourInfo.Colour;

                colourInfo.ApplyChild(colour);

                if (audioData != null)
                {
                    for (int j = 0; j < visualiser_rounds; j++)
                    {
                        for (int i = 0; i < bars_per_visualiser; i++)
                        {
                            if (audioData[i] < amplitude_dead_zone)
                            {
                                continue;
                            }

                            float rotation    = MathHelper.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
                            float rotationCos = (float)Math.Cos(rotation);
                            float rotationSin = (float)Math.Sin(rotation);
                            //taking the cos and sin to the 0..1 range
                            var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;

                            var barSize = new Vector2(size * (float)Math.Sqrt(2 * (1 - Math.Cos(MathHelper.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
                            //The distance between the position and the sides of the bar.
                            var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
                            //The distance between the bottom side of the bar and the top side.
                            var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);

                            var rectangle = new Quad(
                                Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
                                Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
                                Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
                                Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
                                );

                            DrawQuad(
                                texture,
                                rectangle,
                                colourInfo,
                                null,
                                vertexBatch.AddAction,
                                //barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
                                Vector2.Divide(inflation, barSize.Yx));
                        }
                    }
                }

                shader.Unbind();
            }
コード例 #12
0
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                _shader.Bind();

                var inflation = DrawInfo.MatrixInverse.ExtractScale().Xy;

                var colourInfo = DrawColourInfo.Colour;

                colourInfo.ApplyChild(_colour);

                if (_audioData != null)
                {
                    for (var j = 0; j < VisualiserRounds; j++)
                    {
                        for (var i = 0; i < BarsPerVisualiser; i++)
                        {
                            if (_audioData[i] < AmplitudeDeadZone)
                            {
                                continue;
                            }

                            var rotation    = MathUtils.DegreesToRadians(i / (float)BarsPerVisualiser * 360 + j * 360 / VisualiserRounds);
                            var rotationCos = MathF.Cos(rotation);
                            var rotationSin = MathF.Sin(rotation);
                            //taking the cos and sin to the 0..1 range
                            var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * _size;

                            var barSize = new Vector2(_size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / BarsPerVisualiser)))) / 2f, BarLength * _audioData[i]);
                            //The distance between the position and the sides of the bar.
                            var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
                            //The distance between the bottom side of the bar and the top side.
                            var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y);

                            var rectangle = new Quad(
                                Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix),
                                Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix),
                                Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix),
                                Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix)
                                );

                            DrawQuad(
                                _texture,
                                rectangle,
                                colourInfo,
                                null,
                                _vertexBatch.AddAction,
                                //barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that.
                                Vector2.Divide(inflation, barSize.Yx));
                        }
                    }
                }

                _shader.Unbind();
            }
コード例 #13
0
        private void drawEdgeEffect()
        {
            if (MaskingInfo == null || EdgeEffect.Type == EdgeEffectType.None || EdgeEffect.Radius <= 0.0f || EdgeEffect.Colour.Linear.A <= 0.0f)
            {
                return;
            }

            RectangleF effectRect = MaskingInfo.Value.MaskingRect.Inflate(EdgeEffect.Radius).Offset(EdgeEffect.Offset);

            if (!ScreenSpaceMaskingQuad.HasValue)
            {
                ScreenSpaceMaskingQuad = Quad.FromRectangle(effectRect) * DrawInfo.Matrix;
            }

            MaskingInfo edgeEffectMaskingInfo = MaskingInfo.Value;

            edgeEffectMaskingInfo.MaskingRect     = effectRect;
            edgeEffectMaskingInfo.ScreenSpaceAABB = ScreenSpaceMaskingQuad.Value.AABB;
            edgeEffectMaskingInfo.CornerRadius    = MaskingInfo.Value.CornerRadius + EdgeEffect.Radius + EdgeEffect.Roundness;
            edgeEffectMaskingInfo.BorderThickness = 0;
            // HACK HACK HACK. We abuse blend range to give us the linear alpha gradient of
            // the edge effect along its radius using the same rounded-corners shader.
            edgeEffectMaskingInfo.BlendRange         = EdgeEffect.Radius;
            edgeEffectMaskingInfo.AlphaExponent      = 2;
            edgeEffectMaskingInfo.EdgeOffset         = EdgeEffect.Offset;
            edgeEffectMaskingInfo.Hollow             = EdgeEffect.Hollow;
            edgeEffectMaskingInfo.HollowCornerRadius = MaskingInfo.Value.CornerRadius + EdgeEffect.Radius;

            GLWrapper.PushMaskingInfo(edgeEffectMaskingInfo);

            GLWrapper.SetBlend(new BlendingInfo(EdgeEffect.Type == EdgeEffectType.Glow ? BlendingMode.Additive : BlendingMode.Mixture));

            Shader.Bind();

            ColourInfo colour = ColourInfo.SingleColour(EdgeEffect.Colour);

            colour.TopLeft.MultiplyAlpha(DrawColourInfo.Colour.TopLeft.Linear.A);
            colour.BottomLeft.MultiplyAlpha(DrawColourInfo.Colour.BottomLeft.Linear.A);
            colour.TopRight.MultiplyAlpha(DrawColourInfo.Colour.TopRight.Linear.A);
            colour.BottomRight.MultiplyAlpha(DrawColourInfo.Colour.BottomRight.Linear.A);

            Texture.WhitePixel.DrawQuad(
                ScreenSpaceMaskingQuad.Value,
                colour, null, null, null,
                // HACK HACK HACK. We re-use the unused vertex blend range to store the original
                // masking blend range when rendering edge effects. This is needed for smooth inner edges
                // with a hollow edge effect.
                new Vector2(MaskingInfo.Value.BlendRange));

            Shader.Unbind();

            GLWrapper.PopMaskingInfo();
        }
コード例 #14
0
        public ExampleLayer()
        {
            //Create camera
            cameraController = new OrthographicCameraController(1280.0f / 720.0f);

            //Shader library
            shaderLibrary = new ShaderLibrary();

            // ----------
            //Square
            // ----------
            squareVertexArray = IVertexArray.Create();

            float[] squareVertices =
            {
                -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
                0.5f,  -0.5f, 0.0f, 1.0f, 0.0f,
                0.5f,   0.5f, 0.0f, 1.0f, 1.0f,
                -0.5f,  0.5f, 0.0f, 0.0f, 1.0f
            };

            IVertexBuffer squareVertexBuffer = IVertexBuffer.Create(squareVertices, squareVertices.GetBytes());

            BufferLayout squareBufferLayout = new BufferLayout(new[]
            {
                new BufferElement("a_Position", ShaderDataType.Float3),
                new BufferElement("a_TexCoord", ShaderDataType.Float2)
            });

            squareVertexBuffer.SetLayout(squareBufferLayout);
            squareVertexArray.AddVertexBuffer(squareVertexBuffer);

            uint[]       squareIndices     = { 0, 1, 2, 2, 3, 0 };
            IIndexBuffer squareIndexBuffer =
                IIndexBuffer.Create(squareIndices, squareIndices.GetBytes() / sizeof(uint));

            squareVertexArray.SetIndexBuffer(squareIndexBuffer);

            //Square shader
            shaderLibrary.LoadAndAddShader("Shaders/Square.glsl");

            //Texture shader
            IShader textureShader = IShader.Create("Shaders/Texture.glsl");

            shaderLibrary.AddShader(textureShader);

            birdiTexture = I2DTexture.Create("Textures/Birdi.png");
            faceTexture  = I2DTexture.Create("Textures/Face.png");

            textureShader.Bind();
            textureShader.SetInt("u_Texture", 0);
        }
コード例 #15
0
ファイル: AGSRendererLoop.cs プロジェクト: ebrucucen/MonoAGS
        private void removeObjectShader(IShader shader)
        {
            if (shader == null)
            {
                return;
            }

            if (_lastShaderUsed != null)
            {
                _lastShaderUsed.Bind();
            }
            else
            {
                shader.Unbind();
            }
        }
コード例 #16
0
ファイル: Custom geometry.cs プロジェクト: ARLM-Attic/xna-xen
        public void Draw(DrawState state)
        {
            //push the world matrix, multiplying by the current matrix if there is one
            state.PushWorldMatrixMultiply(ref worldMatrix);

            //cull test the custom geometry
            if (geometry.CullTest(state))
            {
                //bind the shader
                shader.Bind(state);

                //draw the custom geometry
                geometry.Draw(state);
            }

            //always pop the matrix afterwards
            state.PopWorldMatrix();
        }
コード例 #17
0
ファイル: 2DRenderer.cs プロジェクト: ejrich/Pretend
        private void Flush(int submissionCount = MaxSubmissions)
        {
            _vertexArray.VertexBuffer.AddData(_submissions.ToArray());
            _submissions.Clear();

            _objectShader.Bind();
            _objectShader.SetMat4("viewProjection", _viewProjection);

            foreach (var(texture, slot) in _textures)
            {
                texture.Bind(slot);
            }

            _textures.Clear();

            _vertexArray.Bind(true);

            _renderContext.Draw(_vertexArray, submissionCount * IndicesInSubmission);
        }
コード例 #18
0
        public override void Draw(Action <TexturedVertex2D> vertexAction)
        {
            base.Draw(vertexAction);

            if (Texture?.Available != true)
            {
                return;
            }

            IShader shader = needsRoundedShader ? RoundedTextureShader : TextureShader;

            shader.Bind();

            Texture.TextureGL.WrapMode = WrapTexture ? TextureWrapMode.Repeat : TextureWrapMode.ClampToEdge;

            Blit(vertexAction);

            shader.Unbind();
        }
コード例 #19
0
ファイル: Draw sphere.cs プロジェクト: ARLM-Attic/xna-xen
        //draw the sphere (This is the method declared in the IDraw interface)
        public void Draw(DrawState state)
        {
            //the DrawState object controls current drawing state for the application.

            //The DrawState uses a number of stacks, it is important to understand how pushing/popping a stack works.

            //First, push the world matrix, multiplying by the current matrix (if there is one).
            //This is very similar to using openGL glPushMatrix() and then glMultMatrix().
            //The DrawState object maintains the world matrix stack, pushing and popping this stack is very fast.
            state.PushWorldMatrixMultiply(ref this.worldMatrix);

            //The next line frustum cull tests the sphere
            //Culltest will return false if the test fails (in this case false would mean the sphere is off screen)
            //The CullTest method requirs an ICuller to be passed in. Here the state object is used because the
            //DrawState object implements the ICuller interface (DrawState's culler performs screen culling)
            //The cull test uses the current world matrix, so make sure you perform the CullTest after applying any
            //transformations.
            //The CullTest method is defined by the ICullable interface. Any IDraw object also implements ICullable.
            if (sphereGeometry.CullTest(state))
            {
                //the sphere is on screen...

                //bind the shader.
                //Note that if the sphere was off screen, the shader would never be bound,
                //which would save valuable CPU time. (The sphere geometry class assumes a shader is bound)
                //This is why the CullTest() method is separate from the Draw() method.
                shader.Bind(state);

                //Once the call to Bind() has been made, the shaders will be active ('bound')
                //on the graphics card. There is no way to 'unbind' or 'end' the shader.
                //Once bound, that shader is in use - until the point a different shader is bound.

                //draw the sphere geometry
                sphereGeometry.Draw(state);
            }

            //always pop the world matrix afterwards
            state.PopWorldMatrix();
        }
コード例 #20
0
        public override void Draw(Action <TexturedVertex2D> vertexAction)
        {
            base.Draw(vertexAction);

            if (Texture?.Available != true || Segments.Count == 0)
            {
                return;
            }

            GLWrapper.PushDepthInfo(DepthInfo.Default);

            IShader shader = needsRoundedShader ? RoundedTextureShader : TextureShader;

            shader.Bind();

            Texture.TextureGL.WrapMode = TextureWrapMode.ClampToEdge;
            Texture.TextureGL.Bind();

            updateVertexBuffer();

            shader.Unbind();

            GLWrapper.PopDepthInfo();
        }
コード例 #21
0
            private void drawBlurredFrameBuffer(int kernelRadius, float sigma, float blurRotation)
            {
                FrameBuffer current = SharedData.CurrentEffectBuffer;
                FrameBuffer target  = SharedData.GetNextEffectBuffer();

                GLWrapper.SetBlend(BlendingParameters.None);

                using (BindFrameBuffer(target))
                {
                    blurShader.GetUniform <int>(@"g_Radius").UpdateValue(ref kernelRadius);
                    blurShader.GetUniform <float>(@"g_Sigma").UpdateValue(ref sigma);

                    Vector2 size = current.Size;
                    blurShader.GetUniform <Vector2>(@"g_TexSize").UpdateValue(ref size);

                    float   radians = -MathUtils.DegreesToRadians(blurRotation);
                    Vector2 blur    = new Vector2(MathF.Cos(radians), MathF.Sin(radians));
                    blurShader.GetUniform <Vector2>(@"g_BlurDirection").UpdateValue(ref blur);

                    blurShader.Bind();
                    DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White));
                    blurShader.Unbind();
                }
            }
コード例 #22
0
            private void drawBlurredFrameBuffer(int kernelRadius, float sigma, float blurRotation)
            {
                FrameBuffer source = currentFrameBuffer;
                FrameBuffer target = advanceFrameBuffer();

                GLWrapper.SetBlend(new BlendingInfo(BlendingMode.None));

                using (bindFrameBuffer(target, source.Size))
                {
                    blurShader.GetUniform <int>(@"g_Radius").UpdateValue(ref kernelRadius);
                    blurShader.GetUniform <float>(@"g_Sigma").UpdateValue(ref sigma);

                    Vector2 size = source.Size;
                    blurShader.GetUniform <Vector2>(@"g_TexSize").UpdateValue(ref size);

                    float   radians = -MathHelper.DegreesToRadians(blurRotation);
                    Vector2 blur    = new Vector2((float)Math.Cos(radians), (float)Math.Sin(radians));
                    blurShader.GetUniform <Vector2>(@"g_BlurDirection").UpdateValue(ref blur);

                    blurShader.Bind();
                    drawFrameBufferToBackBuffer(source, new RectangleF(0, 0, source.Texture.Width, source.Texture.Height), ColourInfo.SingleColour(Color4.White));
                    blurShader.Unbind();
                }
            }
コード例 #23
0
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                if (texture?.Available != true || points == null || points.Count == 0)
                {
                    return;
                }

                shader.Bind();
                texture.TextureGL.Bind();

                Vector2 localInflationAmount = new Vector2(0, 1) * DrawInfo.MatrixInverse.ExtractScale().Xy;

                // We're dealing with a _large_ number of points, so we need to optimise the quadToDraw * drawInfo.Matrix multiplications below
                // for points that are going to be masked out anyway. This allows for higher resolution graphs at larger scales with virtually no performance loss.
                // Since the points are generated in the local coordinate space, we need to convert the screen space masking quad coordinates into the local coordinate space
                RectangleF localMaskingRectangle = (Quad.FromRectangle(GLWrapper.CurrentMaskingInfo.ScreenSpaceAABB) * DrawInfo.MatrixInverse).AABBFloat;

                float separation = drawSize.X / (points.Count - 1);

                for (int i = 0; i < points.Count - 1; i++)
                {
                    float leftX  = i * separation;
                    float rightX = (i + 1) * separation;

                    if (rightX < localMaskingRectangle.Left)
                    {
                        continue;
                    }

                    if (leftX > localMaskingRectangle.Right)
                    {
                        break; // X is always increasing
                    }
                    Color4 frequencyColour = baseColour;

                    // colouring is applied in the order of interest to a viewer.
                    frequencyColour = Interpolation.ValueAt(points[i].MidIntensity / midMax, frequencyColour, midColour, 0, 1);
                    // high end (cymbal) can help find beat, so give it priority over mids.
                    frequencyColour = Interpolation.ValueAt(points[i].HighIntensity / highMax, frequencyColour, highColour, 0, 1);
                    // low end (bass drum) is generally the best visual aid for beat matching, so give it priority over high/mid.
                    frequencyColour = Interpolation.ValueAt(points[i].LowIntensity / lowMax, frequencyColour, lowColour, 0, 1);

                    ColourInfo finalColour = DrawColourInfo.Colour;
                    finalColour.ApplyChild(frequencyColour);

                    Quad quadToDraw;

                    switch (channels)
                    {
                    default:
                    case 2:
                    {
                        float height = drawSize.Y / 2;
                        quadToDraw = new Quad(
                            new Vector2(leftX, height - points[i].Amplitude[0] * height),
                            new Vector2(rightX, height - points[i + 1].Amplitude[0] * height),
                            new Vector2(leftX, height + points[i].Amplitude[1] * height),
                            new Vector2(rightX, height + points[i + 1].Amplitude[1] * height)
                            );
                        break;
                    }

                    case 1:
                    {
                        quadToDraw = new Quad(
                            new Vector2(leftX, drawSize.Y - points[i].Amplitude[0] * drawSize.Y),
                            new Vector2(rightX, drawSize.Y - points[i + 1].Amplitude[0] * drawSize.Y),
                            new Vector2(leftX, drawSize.Y),
                            new Vector2(rightX, drawSize.Y)
                            );
                        break;
                    }
                    }

                    quadToDraw *= DrawInfo.Matrix;
                    DrawQuad(texture, quadToDraw, finalColour, null, vertexBatch.AddAction, Vector2.Divide(localInflationAmount, quadToDraw.Size));
                }

                shader.Unbind();
            }