Example #1
0
            private void drawEdgeEffect()
            {
                if (maskingInfo == null || edgeEffect.Type == EdgeEffectType.None || edgeEffect.Radius <= 0.0f || edgeEffect.Colour.Linear.A <= 0)
                {
                    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);

                DrawQuad(
                    Texture.WhitePixel,
                    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();
            }
            public override void ApplyState()
            {
                base.ApplyState();

                if (!Source.Masking && (Source.BorderThickness != 0.0f || Source.EdgeEffect.Type != EdgeEffectType.None))
                {
                    throw new InvalidOperationException("Can not have border effects/edge effects if masking is disabled.");
                }

                Vector3 scale      = DrawInfo.MatrixInverse.ExtractScale();
                float   blendRange = Source.MaskingSmoothness * (scale.X + scale.Y) / 2;

                // Calculate a shrunk rectangle which is free from corner radius/smoothing/border effects
                float shrinkage = Source.CornerRadius - Source.CornerRadius * cos_45 + blendRange + Source.borderThickness;

                // Normalise to handle negative sizes, and clamp the shrinkage to prevent size from going negative.
                RectangleF shrunkDrawRectangle = Source.DrawRectangle.Normalize();

                shrunkDrawRectangle = shrunkDrawRectangle.Shrink(new Vector2(Math.Min(shrunkDrawRectangle.Width / 2, shrinkage), Math.Min(shrunkDrawRectangle.Height / 2, shrinkage)));

                maskingInfo = !Source.Masking
                    ? (MaskingInfo?)null
                    : new MaskingInfo
                {
                    ScreenSpaceAABB             = Source.ScreenSpaceDrawQuad.AABB,
                    MaskingRect                 = Source.DrawRectangle.Normalize(),
                    ConservativeScreenSpaceQuad = Quad.FromRectangle(shrunkDrawRectangle) * DrawInfo.Matrix,
                    ToMaskingSpace              = DrawInfo.MatrixInverse,
                    CornerRadius                = Source.effectiveCornerRadius,
                    CornerExponent              = Source.CornerExponent,
                    BorderThickness             = Source.BorderThickness,
                    BorderColour                = Source.BorderColour,
                    // We are setting the linear blend range to the approximate size of a _pixel_ here.
                    // This results in the optimal trade-off between crispness and smoothness of the
                    // edges of the masked region according to sampling theory.
                    BlendRange    = blendRange,
                    AlphaExponent = 1,
                };

                edgeEffect             = Source.EdgeEffect;
                screenSpaceMaskingQuad = null;
                Shader = Source.Shader;
                forceLocalVertexBatch = Source.ForceLocalVertexBatch;
                sourceChildrenCount   = Source.internalChildren.Count;
            }
        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   += EdgeEffect.Radius + EdgeEffect.Roundness;
            edgeEffectMaskingInfo.BorderThickness = 0;
            edgeEffectMaskingInfo.BlendRange      = EdgeEffect.Radius;
            edgeEffectMaskingInfo.AlphaExponent   = 2;
            edgeEffectMaskingInfo.Hollow          = EdgeEffect.Hollow;

            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(DrawInfo.Colour.TopLeft.Linear.A);
            colour.BottomLeft.MultiplyAlpha(DrawInfo.Colour.BottomLeft.Linear.A);
            colour.TopRight.MultiplyAlpha(DrawInfo.Colour.TopRight.Linear.A);
            colour.BottomRight.MultiplyAlpha(DrawInfo.Colour.BottomRight.Linear.A);

            Texture.WhitePixel.DrawQuad(ScreenSpaceMaskingQuad.Value, colour);

            Shader.Unbind();

            GLWrapper.PopMaskingInfo();
        }
        private void drawEdgeEffect()
        {
            if (MaskingInfo == null || EdgeEffect.Type == EdgeEffectType.None || EdgeEffect.Radius <= 0.0f || EdgeEffect.Colour.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   += EdgeEffect.Radius + EdgeEffect.Roundness;
            edgeEffectMaskingInfo.BorderThickness = 0;
            edgeEffectMaskingInfo.BlendRange      = EdgeEffect.Radius;

            GLWrapper.PushMaskingInfo(edgeEffectMaskingInfo);

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

            Shader.Bind();

            Color4 colour = EdgeEffect.Colour;

            colour.A *= DrawInfo.Colour.A;

            Texture.WhitePixel.Draw(ScreenSpaceMaskingQuad.Value, colour);

            Shader.Unbind();

            GLWrapper.PopMaskingInfo();
        }
        public bool CheckCollision(Quad birdQuad)
        {
            // Extend the top pipe bounds upwards so it's not possible to simply fly over it.
            RectangleF topPipeRect = topPipe.ScreenSpaceDrawQuad.AABBFloat;

            topPipeRect.Y      -= 5000.0f;
            topPipeRect.Height += 5000.0f;
            Quad topPipeQuad = Quad.FromRectangle(topPipeRect);

            // Bird touched the top pipe
            if (birdQuad.Intersects(topPipeQuad))
            {
                return(true);
            }

            // Bird touched the bottom pipe
            if (birdQuad.Intersects(bottomPipe.ScreenSpaceDrawQuad))
            {
                return(true);
            }

            return(false);
        }
Example #6
0
 /// <summary>
 /// Accepts a rectangle in local coordinates and converts it to a quad in screen space.
 /// </summary>
 /// <param name="input">A rectangle in local coordinates.</param>
 /// <returns>The quad in screen coordinates.</returns>
 public Quad ToScreenSpace(RectangleF input)
 {
     return(Quad.FromRectangle(input) * DrawInfo.Matrix);
 }
Example #7
0
 /// <summary>
 /// Accepts a rectangle in local coordinates and converts it to a quad in Parent's space.
 /// </summary>
 /// <param name="input">A rectangle in local coordinates.</param>
 /// <returns>The quad in Parent's coordinates.</returns>
 public Quad ToParentSpace(RectangleF input)
 {
     return(Quad.FromRectangle(input) * (DrawInfo.Matrix * Parent.DrawInfo.MatrixInverse));
 }
Example #8
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();
            }
            public override void Draw(Action <TexturedVertex2D> vertexAction)
            {
                base.Draw(vertexAction);

                if (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
                    }
                    ColourInfo colour = DrawInfo.Colour;
                    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;
                    Texture.DrawQuad(quadToDraw, colour, null, Shared.VertexBatch.Add, Vector2.Divide(localInflationAmount, quadToDraw.Size));
                }

                Shader.Unbind();
            }