static TextureGLSingle() { QuadBatch <TexturedVertex2D> quadBatch = new QuadBatch <TexturedVertex2D>(512, 128); default_quad_action = quadBatch.AddAction; // We multiply the size param by 3 such that the amount of vertices is a multiple of the amount of vertices // per primitive (triangles in this case). Otherwise overflowing the batch will result in wrong // grouping of vertices into primitives. LinearBatch <TexturedVertex2D> triangleBatch = new LinearBatch <TexturedVertex2D>(512 * 3, 128, PrimitiveType.Triangles); default_triangle_action = triangleBatch.AddAction; }
public override void Draw() { if (Alpha <= 0 || Progress == 0) return; Progress = (float)Math.Min(Progress, 1.0); try { float endAngle = (float)(Progress * (2 * Math.PI) + startAngle); float scaledRadius = Radius * GameBase.WindowManager.Ratio; Vector2 scaledPosition = Position * GameBase.WindowManager.Ratio; float angle1, angle2; if (endAngle < startAngle) { angle1 = endAngle; angle2 = startAngle; } else { angle1 = startAngle; angle2 = endAngle; } if (angle2 > angle1) { OsuGlControl.ColourShader2D.Begin(); if (vertexBatch == null) vertexBatch = new LinearBatch<Vertex2d>(amountPoints + 2, 1, BeginMode.TriangleFan); vertexBatch.Add(new Vertex2d() { Position = scaledPosition, Colour = this.Colour }); Vector2 offset; for (float a = angle1; a < angle2; a += da) { offset = new Vector2((float)Math.Cos(a), (float)Math.Sin(a)) * scaledRadius; vertexBatch.Add(new Vertex2d() { Position = scaledPosition + offset, Colour = this.Colour }); } offset = new Vector2((float)Math.Cos(angle2), (float)Math.Sin(angle2)) * scaledRadius; vertexBatch.Add(new Vertex2d() { Position = scaledPosition + offset, Colour = this.Colour }); vertexBatch.Draw(); OsuGlControl.ColourShader2D.End(); } } catch (InvalidOperationException) { } }
private void updateTriangleBatch() { if (Children == null) { return; } // This logic got roughly copied from the old osu! code base. These constants seem to have worked well so far. int clampedAmountChildren = MathHelper.Clamp(Children.Count, 1, 1000); if (mayHaveOwnVertexBatch(clampedAmountChildren) && (triangleBatch == null || triangleBatch.Size < clampedAmountChildren)) { // The same general idea as updateQuadBatch(), except that each child draws up to 3 vertices * 6 triangles after quad-quad intersection triangleBatch = new LinearBatch <TexturedVertex2D>(clampedAmountChildren * 2 * 3, 500, PrimitiveType.Triangles); } }
public override void DrawTriangle(Triangle vertexTriangle, RectangleF?textureRect, ColourInfo drawColour, Action <TexturedVertex2D> vertexAction = null, Vector2?inflationPercentage = null) { Debug.Assert(!isDisposed); RectangleF texRect = GetTextureRect(textureRect); if (inflationPercentage.HasValue) { texRect = texRect.Inflate(new Vector2(inflationPercentage.Value.X * texRect.Width, inflationPercentage.Value.Y * texRect.Height)); } if (vertexAction == null) { if (triangleBatch == null) { // We multiply the size param by 3 such that the amount of vertices is a multiple of the amount of vertices // per primitive (triangles in this case). Otherwise overflowing the batch will result in wrong // grouping of vertices into primitives. triangleBatch = new LinearBatch <TexturedVertex2D>(512 * 3, 128, PrimitiveType.Triangles); } vertexAction = triangleBatch.Add; } vertexAction(new TexturedVertex2D { Position = vertexTriangle.P0, TexturePosition = new Vector2((texRect.Left + texRect.Right) / 2, texRect.Top), Colour = drawColour.TopLeft.Linear, }); vertexAction(new TexturedVertex2D { Position = vertexTriangle.P1, TexturePosition = new Vector2(texRect.Left, texRect.Bottom), Colour = drawColour.BottomLeft.Linear, }); vertexAction(new TexturedVertex2D { Position = vertexTriangle.P2, TexturePosition = new Vector2(texRect.Right, texRect.Bottom), Colour = drawColour.BottomRight.Linear, }); FrameStatistics.Increment(StatisticsCounterType.KiloPixels, (long)vertexTriangle.ConservativeArea); }
public override void DrawTriangle(Triangle vertexTriangle, RectangleF?textureRect, ColourInfo drawColour, Action <TexturedVertex2D> vertexAction = null, Vector2?inflationPercentage = null) { Debug.Assert(!isDisposed); RectangleF texRect = GetTextureRect(textureRect); if (inflationPercentage.HasValue) { texRect = texRect.Inflate(new Vector2(inflationPercentage.Value.X * texRect.Width, inflationPercentage.Value.Y * texRect.Height)); } if (vertexAction == null) { if (triangleBatch == null) { triangleBatch = new LinearBatch <TexturedVertex2D>(512, 128, PrimitiveType.Triangles); } vertexAction = triangleBatch.Add; } vertexAction(new TexturedVertex2D { Position = vertexTriangle.P0, TexturePosition = new Vector2((texRect.Left + texRect.Right) / 2, texRect.Top), Colour = drawColour.TopLeft.Linear, }); vertexAction(new TexturedVertex2D { Position = vertexTriangle.P1, TexturePosition = new Vector2(texRect.Left, texRect.Bottom), Colour = drawColour.BottomLeft.Linear, }); vertexAction(new TexturedVertex2D { Position = vertexTriangle.P2, TexturePosition = new Vector2(texRect.Right, texRect.Bottom), Colour = drawColour.BottomRight.Linear, }); FrameStatistics.Increment(StatisticsCounterType.KiloPixels, (long)vertexTriangle.ConservativeArea); }
private void updateVertexBuffer() { const float start_angle = 0; float dir = Math.Sign(angle); float radius = Math.Max(drawSize.X, drawSize.Y); // The amount of points are selected such that discrete curvature is smaller than the provided tolerance. // The exact angle required to meet the tolerance is: 2 * Math.Acos(1 - TOLERANCE / r) // The special case is for extremely small circles where the radius is smaller than the tolerance. int amountPoints = 2 * radius <= arc_tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(Math.PI / Math.Acos(1 - arc_tolerance / radius))); if (halfCircleBatch == null || halfCircleBatch.Size < amountPoints * 2) { halfCircleBatch?.Dispose(); // Amount of points is multiplied by 2 to account for each part requiring two vertices. halfCircleBatch = new LinearBatch <TexturedVertex2D>(amountPoints * 2, 1, PrimitiveType.TriangleStrip); } Matrix3 transformationMatrix = DrawInfo.Matrix; MatrixExtensions.ScaleFromLeft(ref transformationMatrix, drawSize); Vector2 current = origin + pointOnCircle(start_angle) * 0.5f; Color4 currentColour = colourAt(current); current = Vector2Extensions.Transform(current, transformationMatrix); Vector2 screenOrigin = Vector2Extensions.Transform(origin, transformationMatrix); Color4 originColour = colourAt(origin); // Offset by 0.5 pixels inwards to ensure we never sample texels outside the bounds RectangleF texRect = texture.GetTextureRect(new RectangleF(0.5f, 0.5f, texture.Width - 1, texture.Height - 1)); float prevOffset = dir >= 0 ? 0 : 1; // First center point halfCircleBatch.Add(new TexturedVertex2D { Position = Vector2.Lerp(current, screenOrigin, innerRadius), TexturePosition = new Vector2(dir >= 0 ? texRect.Left : texRect.Right, texRect.Top), Colour = originColour }); // First outer point. halfCircleBatch.Add(new TexturedVertex2D { Position = new Vector2(current.X, current.Y), TexturePosition = new Vector2(dir >= 0 ? texRect.Left : texRect.Right, texRect.Bottom), Colour = currentColour }); for (int i = 1; i < amountPoints; i++) { float fract = (float)i / (amountPoints - 1); // Clamps the angle so we don't overshoot. // dir is used so negative angles result in negative angularOffset. float angularOffset = Math.Min(fract * two_pi, dir * angle); float normalisedOffset = angularOffset / two_pi; if (dir < 0) { normalisedOffset += 1.0f; } // Update `current` current = origin + pointOnCircle(start_angle + angularOffset) * 0.5f; currentColour = colourAt(current); current = Vector2Extensions.Transform(current, transformationMatrix); // current center point halfCircleBatch.Add(new TexturedVertex2D { Position = Vector2.Lerp(current, screenOrigin, innerRadius), TexturePosition = new Vector2(texRect.Left + (normalisedOffset + prevOffset) / 2 * texRect.Width, texRect.Top), Colour = originColour }); // current outer point halfCircleBatch.Add(new TexturedVertex2D { Position = new Vector2(current.X, current.Y), TexturePosition = new Vector2(texRect.Left + normalisedOffset * texRect.Width, texRect.Bottom), Colour = currentColour }); prevOffset = normalisedOffset; } }
public override void DrawTriangle(Triangle vertexTriangle, RectangleF?textureRect, ColourInfo drawColour, Action <TexturedVertex2D> vertexAction = null, Vector2?inflationPercentage = null) { Debug.Assert(!IsDisposed); RectangleF texRect = GetTextureRect(textureRect); Vector2 inflationAmount = inflationPercentage.HasValue ? new Vector2(inflationPercentage.Value.X * texRect.Width, inflationPercentage.Value.Y * texRect.Height) : Vector2.Zero; RectangleF inflatedTexRect = texRect.Inflate(inflationAmount); if (vertexAction == null) { if (triangleBatch == null) { // We multiply the size param by 3 such that the amount of vertices is a multiple of the amount of vertices // per primitive (triangles in this case). Otherwise overflowing the batch will result in wrong // grouping of vertices into primitives. triangleBatch = new LinearBatch <TexturedVertex2D>(512 * 3, 128, PrimitiveType.Triangles); } vertexAction = triangleBatch.Add; } // We split the triangle into two, such that we can obtain smooth edges with our // texture coordinate trick. We might want to revert this to drawing a single // triangle in case we ever need proper texturing, or if the additional vertices // end up becoming an overhead (unlikely). SRGBColour topColour = (drawColour.TopLeft + drawColour.TopRight) / 2; SRGBColour bottomColour = (drawColour.BottomLeft + drawColour.BottomRight) / 2; // Left triangle half vertexAction(new TexturedVertex2D { Position = vertexTriangle.P0, TexturePosition = new Vector2(inflatedTexRect.Left, inflatedTexRect.Top), TextureRect = new Vector4(texRect.Left, texRect.Top, texRect.Right, texRect.Bottom), BlendRange = inflationAmount, Colour = topColour.Linear, }); vertexAction(new TexturedVertex2D { Position = vertexTriangle.P1, TexturePosition = new Vector2(inflatedTexRect.Left, inflatedTexRect.Bottom), TextureRect = new Vector4(texRect.Left, texRect.Top, texRect.Right, texRect.Bottom), BlendRange = inflationAmount, Colour = drawColour.BottomLeft.Linear, }); vertexAction(new TexturedVertex2D { Position = (vertexTriangle.P1 + vertexTriangle.P2) / 2, TexturePosition = new Vector2((inflatedTexRect.Left + inflatedTexRect.Right) / 2, inflatedTexRect.Bottom), TextureRect = new Vector4(texRect.Left, texRect.Top, texRect.Right, texRect.Bottom), BlendRange = inflationAmount, Colour = bottomColour.Linear, }); // Right triangle half vertexAction(new TexturedVertex2D { Position = vertexTriangle.P0, TexturePosition = new Vector2(inflatedTexRect.Right, inflatedTexRect.Top), TextureRect = new Vector4(texRect.Left, texRect.Top, texRect.Right, texRect.Bottom), BlendRange = inflationAmount, Colour = topColour.Linear, }); vertexAction(new TexturedVertex2D { Position = (vertexTriangle.P1 + vertexTriangle.P2) / 2, TexturePosition = new Vector2((inflatedTexRect.Left + inflatedTexRect.Right) / 2, inflatedTexRect.Bottom), TextureRect = new Vector4(texRect.Left, texRect.Top, texRect.Right, texRect.Bottom), BlendRange = inflationAmount, Colour = bottomColour.Linear, }); vertexAction(new TexturedVertex2D { Position = vertexTriangle.P2, TexturePosition = new Vector2(inflatedTexRect.Right, inflatedTexRect.Bottom), TextureRect = new Vector4(texRect.Left, texRect.Top, texRect.Right, texRect.Bottom), BlendRange = inflationAmount, Colour = drawColour.BottomRight.Linear, }); FrameStatistics.Increment(StatisticsCounterType.KiloPixels, (long)vertexTriangle.ConservativeArea); }
internal PrimitiveBatch(BeginMode type) { vertexBatch = new LinearBatch <Vertex2d>(4000, 1, type); }