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); }
/// <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); }
/// <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)); }
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(); }