public override void Draw(Action<TexturedVertex2D> vertexAction) { updateVertexBatch(); // Prefer to use own vertex batch instead of the parent-owned one. if (Shared.VertexBatch != null) vertexAction = Shared.VertexBatch.AddAction; base.Draw(vertexAction); drawEdgeEffect(); if (MaskingInfo != null) { MaskingInfo info = MaskingInfo.Value; if (info.BorderThickness > 0) info.BorderColour *= DrawColourInfo.Colour.AverageColour; GLWrapper.PushMaskingInfo(info); } if (Children != null) for (int i = 0; i < Children.Count; i++) Children[i].Draw(vertexAction); if (MaskingInfo != null) GLWrapper.PopMaskingInfo(); }
public override void Draw(IVertexBatch vertexBatch) { updateVertexBatch(); // Prefer to use own vertex batch instead of the parent-owned one. if (Shared.VertexBatch != null) { vertexBatch = Shared.VertexBatch; } base.Draw(vertexBatch); drawEdgeEffect(); if (MaskingInfo != null) { GLWrapper.PushMaskingInfo(MaskingInfo.Value); } if (Children != null) { foreach (DrawNode child in Children) { child.Draw(vertexBatch); } } if (MaskingInfo != null) { GLWrapper.PopMaskingInfo(); } }
private InvokeOnDisposal establishFrameBufferViewport(Vector2 roundedSize) { // Disable masking for generating the frame buffer since masking will be re-applied // when actually drawing later on anyways. This allows more information to be captured // in the frame buffer and helps with cached buffers being re-used. Rectangle screenSpaceMaskingRect = new Rectangle((int)Math.Floor(ScreenSpaceDrawRectangle.X), (int)Math.Floor(ScreenSpaceDrawRectangle.Y), (int)roundedSize.X + 1, (int)roundedSize.Y + 1); GLWrapper.PushMaskingInfo(new MaskingInfo { ScreenSpaceAABB = screenSpaceMaskingRect, MaskingRect = ScreenSpaceDrawRectangle, ToMaskingSpace = Matrix3.Identity, BlendRange = 1, AlphaExponent = 1, }, true); // Match viewport to FrameBuffer such that we don't draw unnecessary pixels. GLWrapper.PushViewport(new Rectangle(0, 0, (int)roundedSize.X, (int)roundedSize.Y)); return(new InvokeOnDisposal(delegate { GLWrapper.PopViewport(); GLWrapper.PopMaskingInfo(); })); }
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 Draw(Action <TexturedVertex2D> vertexAction) { if (CustomVertexAction == null) { updateVertexBatch(); // Prefer to use own vertex batch instead of the parent-owned one. if (Shared.VertexBatch != null) { vertexAction = Shared.VertexBatch.Add; } } else { vertexAction = CustomVertexAction; } base.Draw(vertexAction); drawEdgeEffect(); if (MaskingInfo != null) { MaskingInfo info = MaskingInfo.Value; if (info.BorderThickness > 0) { info.BorderColour *= DrawInfo.Colour.AverageColour; } GLWrapper.PushMaskingInfo(info); } if (Children != null) { foreach (DrawNode child in Children) { child.Draw(vertexAction); } } if (MaskingInfo != null) { GLWrapper.PopMaskingInfo(); } }
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(); }
protected virtual void DrawChildrenOpaqueInteriors(DepthValue depthValue, Action <TexturedVertex2D> vertexAction) { bool canIncrement = depthValue.CanIncrement; // Assume that if we can't increment the depth value, no child can, thus nothing will be drawn. if (canIncrement) { updateTriangleBatch(); // Prefer to use own vertex batch instead of the parent-owned one. if (triangleBatch != null) { vertexAction = triangleBatch.AddAction; } if (maskingInfo != null) { GLWrapper.PushMaskingInfo(maskingInfo.Value); } } // We still need to invoke this method recursively for all children so their depth value is updated if (Children != null) { for (int i = Children.Count - 1; i >= 0; i--) { Children[i].DrawOpaqueInteriorSubTree(depthValue, vertexAction); } } // Assume that if we can't increment the depth value, no child can, thus nothing will be drawn. if (canIncrement) { if (maskingInfo != null) { GLWrapper.PopMaskingInfo(); } } }
public override void Draw(Action <TexturedVertex2D> vertexAction) { updateQuadBatch(); // Prefer to use own vertex batch instead of the parent-owned one. if (quadBatch != null) { vertexAction = quadBatch.AddAction; } base.Draw(vertexAction); drawEdgeEffect(); if (maskingInfo != null) { MaskingInfo info = maskingInfo.Value; if (info.BorderThickness > 0) { info.BorderColour = ColourInfo.Multiply(info.BorderColour, DrawColourInfo.Colour); } GLWrapper.PushMaskingInfo(info); } if (Children != null) { for (int i = 0; i < Children.Count; i++) { Children[i].Draw(vertexAction); } } if (maskingInfo != null) { 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(); }
private IDisposable establishFrameBufferViewport() { // Disable masking for generating the frame buffer since masking will be re-applied // when actually drawing later on anyways. This allows more information to be captured // in the frame buffer and helps with cached buffers being re-used. RectangleI screenSpaceMaskingRect = new RectangleI((int)Math.Floor(screenSpaceDrawRectangle.X), (int)Math.Floor(screenSpaceDrawRectangle.Y), (int)frameBufferSize.X + 1, (int)frameBufferSize.Y + 1); GLWrapper.PushMaskingInfo(new MaskingInfo { ScreenSpaceAABB = screenSpaceMaskingRect, MaskingRect = screenSpaceDrawRectangle, ToMaskingSpace = Matrix3.Identity, BlendRange = 1, AlphaExponent = 1, }, true); // Match viewport to FrameBuffer such that we don't draw unnecessary pixels. GLWrapper.PushViewport(new RectangleI(0, 0, (int)frameBufferSize.X, (int)frameBufferSize.Y)); GLWrapper.PushScissor(new RectangleI(0, 0, (int)frameBufferSize.X, (int)frameBufferSize.Y)); GLWrapper.PushScissorOffset(screenSpaceMaskingRect.Location); return(new ValueInvokeOnDisposal <BufferedDrawNode>(this, d => d.returnViewport())); }