private void checkForCorrectness()
        {
            Quad?scaling1LastQuad      = null;
            Quad?scaling2LastQuad      = null;
            Quad?scalingTargetLastQuad = null;

            AddUntilStep("ensure dimensions don't change", () =>
            {
                if (scaling1LastQuad.HasValue && scaling2LastQuad.HasValue)
                {
                    // check inter-frame changes to make sure they match expectations.
                    Assert.That(scaling1.ScreenSpaceDrawQuad.AlmostEquals(scaling1LastQuad.Value), Is.True);
                    Assert.That(scaling2.ScreenSpaceDrawQuad.AlmostEquals(scaling2LastQuad.Value), Is.True);
                }

                scaling1LastQuad = scaling1.ScreenSpaceDrawQuad;
                scaling2LastQuad = scaling2.ScreenSpaceDrawQuad;

                // wait for scaling to stop.
                bool scalingFinished = scalingTargetLastQuad.HasValue && scaleTarget.ScreenSpaceDrawQuad.AlmostEquals(scalingTargetLastQuad.Value);

                scalingTargetLastQuad = scaleTarget.ScreenSpaceDrawQuad;

                return(scalingFinished);
            });
        }
示例#2
0
            public override void ApplyState()
            {
                base.ApplyState();

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

                Vector3 scale = DrawInfo.MatrixInverse.ExtractScale();

                maskingInfo = !Source.Masking
                    ? (MaskingInfo?)null
                    : new MaskingInfo
                {
                    ScreenSpaceAABB = Source.ScreenSpaceDrawQuad.AABB,
                    MaskingRect     = Source.DrawRectangle,
                    ToMaskingSpace  = DrawInfo.MatrixInverse,
                    CornerRadius    = Source.CornerRadius,
                    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    = Source.MaskingSmoothness * (scale.X + scale.Y) / 2,
                    AlphaExponent = 1,
                };

                edgeEffect             = Source.EdgeEffect;
                screenSpaceMaskingQuad = null;
                Shader = Source.Shader;
                forceLocalVertexBatch = Source.ForceLocalVertexBatch;
            }
示例#3
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();
            }
示例#4
0
        /// <summary>Debug print a <see cref="Quad"/>.</summary>
        public static string Print(Quad?quad)
        {
            if (quad is null)
            {
                return("null");
            }

            return($"{Print(quad.Subject, false)} " +
                   $"{Print(quad.Predicate, false)} " +
                   $"{Print(quad.Object, false)} .");
        }
            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 void Process(Interval <int> interval, ITextString match)
            {
                //var matrix = page.RotateMatrix;
                // Defining the highlight box of the text pattern match...
                IList <Quad> highlightQuads = new List <Quad>();

                {
                    /*
                     * NOTE: A text pattern match may be split across multiple contiguous lines,
                     * so we have to define a distinct highlight box for each text chunk.
                     */
                    Quad?textQuad = null;
                    foreach (TextChar textChar in match.TextChars)
                    {
                        var textCharQuad = textChar.Quad;
                        if (!textQuad.HasValue)
                        {
                            textQuad = textCharQuad;
                        }
                        else
                        {
                            if (textCharQuad.Top > textQuad.Value.Bottom)
                            {
                                highlightQuads.Add(textQuad.Value);
                                textQuad = textCharQuad;
                            }
                            else
                            {
                                textQuad = Quad.Union(textQuad.Value, textCharQuad);
                            }
                        }
                    }
                    highlightQuads.Add(textQuad.Value);
                }
                // Highlight the text pattern match!
                new TextMarkup(page, highlightQuads, null, TextMarkupType.Highlight);
            }
示例#9
0
 public void Invalidate()
 {
     text = null;
     quad = null;
 }
示例#10
0
 /// <inheritdoc />
 public bool Equals(Quad?x, Quad?y)
 => x?.Subject == y?.Subject;