private void addLineCap(Vector2 origin, float theta, float thetaDiff, RectangleF texRect) { const float step = MathF.PI / MAX_RES; float dir = Math.Sign(thetaDiff); thetaDiff = dir * thetaDiff; int amountPoints = (int)Math.Ceiling(thetaDiff / step); if (dir < 0) { theta += MathF.PI; } Vector2 current = origin + pointOnCircle(theta) * radius; Color4 currentColour = colourAt(current); current = Vector2Extensions.Transform(current, DrawInfo.Matrix); Vector2 screenOrigin = Vector2Extensions.Transform(origin, DrawInfo.Matrix); Color4 originColour = colourAt(origin); for (int i = 1; i <= amountPoints; i++) { // Center point halfCircleBatch.Add(new TexturedVertex3D { Position = new Vector3(screenOrigin.X, screenOrigin.Y, 1), TexturePosition = new Vector2(texRect.Right, texRect.Centre.Y), Colour = originColour }); // First outer point halfCircleBatch.Add(new TexturedVertex3D { Position = new Vector3(current.X, current.Y, 0), TexturePosition = new Vector2(texRect.Left, texRect.Centre.Y), Colour = currentColour }); float angularOffset = Math.Min(i * step, thetaDiff); current = origin + pointOnCircle(theta + dir * angularOffset) * radius; currentColour = colourAt(current); current = Vector2Extensions.Transform(current, DrawInfo.Matrix); // Second outer point halfCircleBatch.Add(new TexturedVertex3D { Position = new Vector3(current.X, current.Y, 0), TexturePosition = new Vector2(texRect.Left, texRect.Centre.Y), Colour = currentColour }); } }
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) { } }
/// <summary> /// AddVertex is called to add another vertex to be rendered. To draw a point, /// AddVertex must be called once. for lines, twice, and for triangles 3 times. /// this function can only be called once begin has been called. /// </summary> /// <param name="pos">The position of the vertex.</param> /// <param name="colour">The colour of the vertex.</param> internal void AddVertex(Vector2 pos, Color colour) { vertexBatch.Add(new Vertex2d() { Position = pos, Colour = colour }); }
private void HalfCircle(Vector2 pos, float radius, float startAngle, float arcLength, Color globalColour, bool shade, int res) { float da = arcLength / res; Color colour = shade ? new Color(globalColour.R, globalColour.G, globalColour.B, (byte)(Math.Max(0, globalColour.A - 30))) : globalColour; Vertex2d middleVertex = new Vertex2d() { Position = pos, Colour = colour }; Vertex2d previousVertex = new Vertex2d(); float endAngle = (float)(arcLength + startAngle); float a = startAngle; for (int i = 0; i <= res; ++i) { if (shade) { double alpha = Math.Sin(Math.Abs(a - startAngle - Math.PI / 2)); colour = new Color(globalColour.R, globalColour.G, globalColour.B, (byte)(Math.Max(0, globalColour.A - 30 * (1.0 - alpha)))); } Vector2 offset = new Vector2((float)Math.Cos(a), (float)Math.Sin(a)); Vertex2d currentVertex = new Vertex2d() { Position = pos + offset * radius, Colour = colour }; if (i > 0) { triangleFanBatch.Add(middleVertex); triangleFanBatch.Add(currentVertex); triangleFanBatch.Add(previousVertex); } previousVertex = currentVertex; a += da; if (a > endAngle) { a = endAngle; } } }
/// <summary> /// Renders a half-circle using multiple triangles as approximation. Assuming discrete points along the half circle are sampled /// each triangle consists of 2 such neighboring points and the center point of the circle. /// </summary> /// <param name="count">The amount of discrete points to use for approximating the circle.</param> /// <param name="m">A transformation matrix used to obtain the actual positions of each vertex.</param> private void glDrawHalfCircle(int count, Matrix m) { Debug.Assert(count <= MAXRES); if (count == 0) { return; } Vector3 centerPoint = Vector3.Transform(new Vector3(0, 0, 1.0f), m); Vector3 currentPoint = Vector3.Transform(vertices[0], m); for (int i = 0; i <= count - 1; i++) { // Center point halfCircleBatch.Add(new TexturedVertex3d() { Position = centerPoint, TexturePosition = new Vector2(1.0f - 1.0f / (float)TextureSize.Width, 0), Colour = Color.White }); // First outer point halfCircleBatch.Add(new TexturedVertex3d() { Position = currentPoint, TexturePosition = new Vector2(0, 0), Colour = Color.White }); currentPoint = Vector3.Transform(vertices[i + 1], m); // Second outer point halfCircleBatch.Add(new TexturedVertex3d() { Position = currentPoint, TexturePosition = new Vector2(0, 0), Colour = Color.White }); } }
private void updateVertexBuffer() { const float start_angle = 0; const float step = MathHelper.Pi / MAX_RES; float dir = Math.Sign(angle); int amountPoints = (int)Math.Ceiling(Math.Abs(angle) / step); 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++) { // Clamps the angle so we don't overshoot. // dir is used so negative angles result in negative angularOffset. float angularOffset = dir * Math.Min(i * step, dir * angle); float normalisedOffset = angularOffset / MathHelper.TwoPi; 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; } }
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; } }
/// <summary> /// Render a gradient into a 256x1 texture. /// </summary> private TextureGl RenderSliderTexture(Color shadow, Color border, Color InnerColour, Color OuterColour, float aa_width) { using (RenderTarget2D target = new RenderTarget2D(TEX_WIDTH, 1)) { target.Bind(); GL.Disable(EnableCap.DepthTest); GL.Disable(EnableCap.Blend); GL.ClearColor(0.859f, 0.439f, 0.576f, 1.0f); GL.Clear(ClearBufferMask.ColorBufferBit); GL.ClearColor(0, 0, 0, 0); OsuGlControl.ColourShader2D.Properties[@"g_ProjMatrix"] = OpenTK.Matrix4.CreateOrthographicOffCenter(0.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f); OsuGlControl.ColourShader2D.Begin(); lineBatch.Add(new Vertex2d() { Position = new Vector2(-0.5f, 0.0f), Colour = Color.TransparentBlack }); lineBatch.Add(new Vertex2d() { Position = new Vector2(0.0f, 0.0f), Colour = Color.TransparentBlack }); lineBatch.Add(new Vertex2d() { Position = new Vector2(0.078125f - aa_width, 0.0f), Colour = shadow }); lineBatch.Add(new Vertex2d() { Position = new Vector2(0.078125f + aa_width, 0.0f), Colour = border }); lineBatch.Add(new Vertex2d() { Position = new Vector2(0.1875f - aa_width, 0.0f), Colour = border }); lineBatch.Add(new Vertex2d() { Position = new Vector2(0.1875f + aa_width, 0.0f), Colour = OuterColour }); lineBatch.Add(new Vertex2d() { Position = new Vector2(1.0f, 0.0f), Colour = InnerColour }); lineBatch.Add(new Vertex2d() { Position = new Vector2(1.5f, 0.0f), Colour = InnerColour }); lineBatch.Draw(); OsuGlControl.ColourShader2D.End(); OsuGlControl.ColourShader2D.Properties[@"g_ProjMatrix"] = OsuGlControl.ProjectionMatrix; if (!OsuGlControl.CanUseFBO) { //We must re-clear the backbuffer target.Unbind(); GL.Clear(ClearBufferMask.ColorBufferBit); } GL.Enable(EnableCap.Blend); return(target.Texture); } }