Revert "Feature/shader radial menu" due to shader issue (#36470)
This commit is contained in:
committed by
GitHub
parent
86620dbe6c
commit
e6e60dead4
@@ -1,23 +1,12 @@
|
|||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Controls;
|
namespace Content.Client.UserInterface.Controls;
|
||||||
|
|
||||||
[Virtual]
|
[Virtual]
|
||||||
public class RadialContainer : LayoutContainer
|
public class RadialContainer : LayoutContainer
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly IClyde _clyde= default!;
|
|
||||||
private readonly ShaderInstance _shader;
|
|
||||||
|
|
||||||
private readonly float[] _angles = new float[64];
|
|
||||||
private readonly float[] _sectorMedians = new float[64];
|
|
||||||
private readonly Color[] _sectorColors = new Color[64];
|
|
||||||
private readonly Color[] _borderColors = new Color[64];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increment of radius per child element to be rendered.
|
/// Increment of radius per child element to be rendered.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -35,7 +24,11 @@ public class RadialContainer : LayoutContainer
|
|||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public Vector2 AngularRange
|
public Vector2 AngularRange
|
||||||
{
|
{
|
||||||
get => _angularRange;
|
get
|
||||||
|
{
|
||||||
|
return _angularRange;
|
||||||
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
var x = value.X;
|
var x = value.X;
|
||||||
@@ -96,9 +89,7 @@ public class RadialContainer : LayoutContainer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public RadialContainer()
|
public RadialContainer()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
_shader = _prototypeManager.Index<ShaderPrototype>("RadialMenu")
|
|
||||||
.InstanceUnique();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -170,67 +161,6 @@ public class RadialContainer : LayoutContainer
|
|||||||
return base.ArrangeOverride(finalSize);
|
return base.ArrangeOverride(finalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Draw(DrawingHandleScreen handle)
|
|
||||||
{
|
|
||||||
base.Draw(handle);
|
|
||||||
|
|
||||||
float selectedFrom = 0;
|
|
||||||
float selectedTo = 0;
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
foreach (var child in Children)
|
|
||||||
{
|
|
||||||
if (child is not IRadialMenuItemWithSector menuWithSector)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_angles[i] = menuWithSector.AngleSectorTo;
|
|
||||||
_sectorMedians[i] = (menuWithSector.AngleSectorTo + menuWithSector.AngleSectorFrom) / 2;
|
|
||||||
|
|
||||||
if (menuWithSector.IsHovered)
|
|
||||||
{
|
|
||||||
// menuWithSector.DrawBackground;
|
|
||||||
// menuWithSector.DrawBorder;
|
|
||||||
_sectorColors[i] = menuWithSector.HoverBackgroundColor;
|
|
||||||
_borderColors[i] = menuWithSector.HoverBorderColor;
|
|
||||||
selectedFrom = menuWithSector.AngleSectorFrom;
|
|
||||||
selectedTo = menuWithSector.AngleSectorTo;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_sectorColors[i] = menuWithSector.BackgroundColor;
|
|
||||||
_borderColors[i] = menuWithSector.BorderColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var screenSize = _clyde.ScreenSize;
|
|
||||||
|
|
||||||
var menuCenter = new Vector2(
|
|
||||||
ScreenCoordinates.X + (Size.X / 2) * UIScale,
|
|
||||||
screenSize.Y - ScreenCoordinates.Y - (Size.Y / 2) * UIScale
|
|
||||||
);
|
|
||||||
|
|
||||||
_shader.SetParameter("separatorAngles", _angles);
|
|
||||||
_shader.SetParameter("sectorMedianAngles", _sectorMedians);
|
|
||||||
_shader.SetParameter("selectedFrom", selectedFrom);
|
|
||||||
_shader.SetParameter("selectedTo", selectedTo);
|
|
||||||
_shader.SetParameter("childCount", i);
|
|
||||||
_shader.SetParameter("sectorColors", _sectorColors);
|
|
||||||
_shader.SetParameter("borderColors", _borderColors);
|
|
||||||
_shader.SetParameter("centerPos", menuCenter);
|
|
||||||
_shader.SetParameter("screenSize", screenSize);
|
|
||||||
_shader.SetParameter("innerRadius", CalculatedRadius * InnerRadiusMultiplier * UIScale);
|
|
||||||
_shader.SetParameter("outerRadius", CalculatedRadius * OuterRadiusMultiplier * UIScale);
|
|
||||||
|
|
||||||
handle.UseShader(_shader);
|
|
||||||
handle.DrawRect(new UIBox2(0, 0, screenSize.X, screenSize.Y), Color.White);
|
|
||||||
handle.UseShader(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies the different radial alignment modes
|
/// Specifies the different radial alignment modes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -362,12 +362,12 @@ public interface IRadialMenuItemWithSector
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Angle in radian where button sector should start.
|
/// Angle in radian where button sector should start.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float AngleSectorFrom { set; get; }
|
public float AngleSectorFrom { set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Angle in radian where button sector should end.
|
/// Angle in radian where button sector should end.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float AngleSectorTo { set; get; }
|
public float AngleSectorTo { set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Outer radius for drawing segment and pointer detection.
|
/// Outer radius for drawing segment and pointer detection.
|
||||||
@@ -388,41 +388,6 @@ public interface IRadialMenuItemWithSector
|
|||||||
/// Coordinates of center in parent component - button container.
|
/// Coordinates of center in parent component - button container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector2 ParentCenter { set; }
|
public Vector2 ParentCenter { set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marker, is menu item hovered currently.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsHovered { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Color for menu item background when it is hovered over.
|
|
||||||
/// </summary>
|
|
||||||
Color HoverBackgroundColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Color for menu item default state.
|
|
||||||
/// </summary>
|
|
||||||
Color BackgroundColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Color for menu item border when item is hovered over.
|
|
||||||
/// </summary>
|
|
||||||
Color HoverBorderColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Color for menu item border default state.
|
|
||||||
/// </summary>
|
|
||||||
Color BorderColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marker, if menu item background should be drawn.
|
|
||||||
/// </summary>
|
|
||||||
public bool DrawBackground { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marker, if menu item borders should be drawn.
|
|
||||||
/// </summary>
|
|
||||||
public bool DrawBorder { get; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Virtual]
|
[Virtual]
|
||||||
@@ -448,7 +413,7 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia
|
|||||||
/// Marker, that controls if border of segment should be rendered. Is false by default.
|
/// Marker, that controls if border of segment should be rendered. Is false by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Default color of border is same as color of background. Use <see cref="BorderColor"/>
|
/// By default color of border is same as color of background. Use <see cref="BorderColor"/>
|
||||||
/// and <see cref="HoverBorderColor"/> to change it.
|
/// and <see cref="HoverBorderColor"/> to change it.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public bool DrawBorder { get; set; } = false;
|
public bool DrawBorder { get; set; } = false;
|
||||||
@@ -494,6 +459,12 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia
|
|||||||
set => _hoverBorderColorSrgb = Color.ToSrgb(value);
|
set => _hoverBorderColorSrgb = Color.ToSrgb(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Color of separator lines.
|
||||||
|
/// Separator lines are used to visually separate sector of radial menu items.
|
||||||
|
/// </summary>
|
||||||
|
public Color SeparatorColor { get; set; } = new Color(128, 128, 128, 128);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
float IRadialMenuItemWithSector.AngleSectorFrom
|
float IRadialMenuItemWithSector.AngleSectorFrom
|
||||||
{
|
{
|
||||||
@@ -502,7 +473,6 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia
|
|||||||
_angleSectorFrom = value;
|
_angleSectorFrom = value;
|
||||||
_isWholeCircle = IsWholeCircle(value, _angleSectorTo);
|
_isWholeCircle = IsWholeCircle(value, _angleSectorTo);
|
||||||
}
|
}
|
||||||
get => _angleSectorFrom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -513,7 +483,6 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia
|
|||||||
_angleSectorTo = value;
|
_angleSectorTo = value;
|
||||||
_isWholeCircle = IsWholeCircle(_angleSectorFrom, value);
|
_isWholeCircle = IsWholeCircle(_angleSectorFrom, value);
|
||||||
}
|
}
|
||||||
get => _angleSectorTo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -535,6 +504,44 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Draw(DrawingHandleScreen handle)
|
||||||
|
{
|
||||||
|
base.Draw(handle);
|
||||||
|
|
||||||
|
if (_parentCenter == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw sector where space that button occupies actually is
|
||||||
|
var containerCenter = (_parentCenter.Value - Position) * UIScale;
|
||||||
|
|
||||||
|
var angleFrom = _angleSectorFrom + _angleOffset;
|
||||||
|
var angleTo = _angleSectorTo + _angleOffset;
|
||||||
|
if (DrawBackground)
|
||||||
|
{
|
||||||
|
var segmentColor = DrawMode == DrawModeEnum.Hover
|
||||||
|
? _hoverBackgroundColorSrgb
|
||||||
|
: _backgroundColorSrgb;
|
||||||
|
|
||||||
|
DrawAnnulusSector(handle, containerCenter, _innerRadius * UIScale, _outerRadius * UIScale, angleFrom, angleTo, segmentColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DrawBorder)
|
||||||
|
{
|
||||||
|
var borderColor = DrawMode == DrawModeEnum.Hover
|
||||||
|
? _hoverBorderColorSrgb
|
||||||
|
: _borderColorSrgb;
|
||||||
|
DrawAnnulusSector(handle, containerCenter, _innerRadius * UIScale, _outerRadius * UIScale, angleFrom, angleTo, borderColor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isWholeCircle && DrawBorder)
|
||||||
|
{
|
||||||
|
DrawSeparatorLines(handle, containerCenter, _innerRadius * UIScale, _outerRadius * UIScale, angleFrom, angleTo, SeparatorColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override bool HasPoint(Vector2 point)
|
protected override bool HasPoint(Vector2 point)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Robust.Client.GameObjects;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Client.Input;
|
using Robust.Client.Input;
|
||||||
using Robust.Shared.Collections;
|
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Controls;
|
namespace Content.Client.UserInterface.Controls;
|
||||||
|
|
||||||
@@ -174,7 +173,7 @@ public partial class SimpleRadialMenu : RadialMenu
|
|||||||
|
|
||||||
private void ClearExistingChildrenRadialButtons()
|
private void ClearExistingChildrenRadialButtons()
|
||||||
{
|
{
|
||||||
var toRemove = new ValueList<Control>(ChildCount);
|
var toRemove = new List<Control>(ChildCount);
|
||||||
foreach (var child in Children)
|
foreach (var child in Children)
|
||||||
{
|
{
|
||||||
if (child != ContextualButton && child != MenuOuterAreaButton)
|
if (child != ContextualButton && child != MenuOuterAreaButton)
|
||||||
|
|||||||
@@ -108,9 +108,4 @@
|
|||||||
- type: shader
|
- type: shader
|
||||||
id: Hologram
|
id: Hologram
|
||||||
kind: source
|
kind: source
|
||||||
path: "/Textures/Shaders/hologram.swsl"
|
path: "/Textures/Shaders/hologram.swsl"
|
||||||
|
|
||||||
- type: shader
|
|
||||||
id: RadialMenu
|
|
||||||
kind: source
|
|
||||||
path: "/Textures/Shaders/radial-menu.swsl"
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
const highp float Thickness = 0.002;
|
|
||||||
|
|
||||||
const highp float pi = 3.14159265;
|
|
||||||
const highp float twopi = 2.0 * pi;
|
|
||||||
const highp float halfpi = 0.5 * pi;
|
|
||||||
const highp float invpi = 1.0 / pi;
|
|
||||||
|
|
||||||
uniform highp float innerRadius;
|
|
||||||
uniform highp float outerRadius;
|
|
||||||
|
|
||||||
uniform highp vec4[64] sectorColors;
|
|
||||||
uniform highp vec4[64] borderColors;
|
|
||||||
|
|
||||||
uniform highp float[64] separatorAngles;
|
|
||||||
uniform highp float[64] sectorMedianAngles;
|
|
||||||
uniform highp int childCount;
|
|
||||||
uniform highp vec2 centerPos;
|
|
||||||
|
|
||||||
uniform highp float selectedFrom;
|
|
||||||
uniform highp float selectedTo;
|
|
||||||
uniform highp vec2 screenSize;
|
|
||||||
|
|
||||||
highp float SMOOTH(highp float r, highp float R)
|
|
||||||
{
|
|
||||||
return 1.0 - smoothstep(R - 1.0, R + 1.0, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// line from center of circle to radius (outer arg) on theta0 angle (radian,)
|
|
||||||
highp float separator(highp vec2 d, highp float r, highp float outer, highp float theta0, highp float thickness)
|
|
||||||
{
|
|
||||||
// rotate due to difference in coordinate spaces between shaders and ui
|
|
||||||
highp float theta1 = theta0 - halfpi;
|
|
||||||
highp vec2 p = outer * vec2(cos(theta1), -sin(theta1));
|
|
||||||
highp float l = length(d - p * clamp(dot(d, p) / dot(p, p), 0.0, 1.0));
|
|
||||||
return SMOOTH(l, thickness);
|
|
||||||
}
|
|
||||||
|
|
||||||
highp float circle(highp float r, highp float radius, highp float width)
|
|
||||||
{
|
|
||||||
return SMOOTH(r - width / 2.0, radius) - SMOOTH(r + width / 2.0, radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get angle between current point and circle center
|
|
||||||
highp float getAngle(highp vec2 d)
|
|
||||||
{
|
|
||||||
highp vec2 n = normalize(d);
|
|
||||||
highp float angle = acos(n.x);
|
|
||||||
int isNegativeY = int(n.y < 0.0);
|
|
||||||
angle = angle + (twopi - angle * 2) * isNegativeY;
|
|
||||||
// rotate
|
|
||||||
angle = mod(angle - halfpi, twopi);
|
|
||||||
return angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
highp float pcurve(highp float x, highp float a, highp float b )
|
|
||||||
{
|
|
||||||
highp float k = pow(a + b,a + b) / (pow(a, a) * pow(b, b));
|
|
||||||
return k * pow(x, a) * pow(1.0 - x, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets alpha for radial gradients based on pcurve
|
|
||||||
highp float fillGradient(highp float r, highp float inner, highp float outer)
|
|
||||||
{
|
|
||||||
highp float nInner = inner / outer;
|
|
||||||
highp float nR = r / outer;
|
|
||||||
return pcurve(nR, nInner, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fragment()
|
|
||||||
{
|
|
||||||
highp vec4 col = vec4(0.0);
|
|
||||||
|
|
||||||
//angle of the line
|
|
||||||
highp vec2 d = FRAGCOORD.xy - centerPos;
|
|
||||||
highp float angle = getAngle(d);
|
|
||||||
|
|
||||||
highp float r = length(FRAGCOORD.xy - centerPos);
|
|
||||||
// fill sectors
|
|
||||||
int isInsideRange = int(r > innerRadius && r < outerRadius);
|
|
||||||
highp float g = fillGradient(r, innerRadius, outerRadius);
|
|
||||||
|
|
||||||
// trying to mix in color per button
|
|
||||||
|
|
||||||
highp float from = 0;
|
|
||||||
for (int i = 0; i < childCount; i++)
|
|
||||||
{
|
|
||||||
highp float to = separatorAngles[i];
|
|
||||||
int isInSector = int(angle > from && angle < to);
|
|
||||||
col += isInsideRange
|
|
||||||
* vec4(sectorColors[i].xyz , g)* isInSector;
|
|
||||||
|
|
||||||
from = to;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get step of radial menu buttons in radian
|
|
||||||
highp float halfSectorAngleSize = (separatorAngles[1] - separatorAngles[0]) * 0.5;
|
|
||||||
|
|
||||||
for (int i = 0; i < childCount; i++)
|
|
||||||
{
|
|
||||||
highp float sectorMedian = sectorMedianAngles[i];
|
|
||||||
highp float sectorMedianToAngleDiff = abs(sectorMedian - angle);
|
|
||||||
highp vec4 borderColor = borderColors[i];
|
|
||||||
highp vec4 borderColorLight = borderColor * 0.6;
|
|
||||||
int isInInnerRadius = int(r > innerRadius);
|
|
||||||
highp float iAngle = twopi - separatorAngles[i];
|
|
||||||
// button separators
|
|
||||||
highp float sectorFromAngle;
|
|
||||||
int isCurrentZero = int(i > 0);
|
|
||||||
sectorFromAngle = separatorAngles[i - 1] * isCurrentZero;
|
|
||||||
|
|
||||||
col += isInInnerRadius
|
|
||||||
* separator(d, r, outerRadius, sectorFromAngle, 0.5) * borderColor;
|
|
||||||
col += isInInnerRadius
|
|
||||||
* separator(d, r, outerRadius, iAngle, 0.5) * borderColor;
|
|
||||||
|
|
||||||
// set up decorations
|
|
||||||
// inner button 'square' decoration
|
|
||||||
int isInInnerBorderRange = int(r > innerRadius + 15);
|
|
||||||
col += isInInnerRadius * isInInnerBorderRange
|
|
||||||
* separator(d, r, outerRadius - 15, twopi - sectorMedian - halfSectorAngleSize * 0.8, 1.0) * 0.2 * borderColorLight;
|
|
||||||
col += isInInnerRadius * isInInnerBorderRange
|
|
||||||
* separator(d, r, outerRadius - 15, twopi - sectorMedian + halfSectorAngleSize * 0.8, 1.0) * 0.2 * borderColorLight;
|
|
||||||
|
|
||||||
int isInInnerBorderSector = int(sectorMedianToAngleDiff < halfSectorAngleSize * 0.8);
|
|
||||||
col += isInInnerRadius * isInInnerBorderRange * isInInnerBorderSector
|
|
||||||
* circle(r, innerRadius + 15, 2.0) * 0.2 * borderColorLight;
|
|
||||||
col += isInInnerRadius * isInInnerBorderRange * isInInnerBorderSector
|
|
||||||
* circle(r, outerRadius - 15, 2.0) * 0.2 * borderColorLight;
|
|
||||||
|
|
||||||
// outer button decorative elements
|
|
||||||
int isInOuterBorderOuterSector = int(sectorMedianToAngleDiff < halfSectorAngleSize * 0.2);
|
|
||||||
col += isInOuterBorderOuterSector
|
|
||||||
* circle(r, innerRadius - 5, 4.0) * 0.4 * borderColor;
|
|
||||||
|
|
||||||
int isInOuterBorderInnerSector = int(sectorMedianToAngleDiff < halfSectorAngleSize * 0.6);
|
|
||||||
col += isInOuterBorderInnerSector
|
|
||||||
* circle(r, outerRadius + 10, 4.0) * 0.4 * borderColor;
|
|
||||||
|
|
||||||
// outer and inner circle of sectors
|
|
||||||
int isOnSectorBorder = int(sectorMedianToAngleDiff < halfSectorAngleSize);
|
|
||||||
col += isOnSectorBorder
|
|
||||||
* circle(r, innerRadius, 2.0) * borderColor;
|
|
||||||
col += isOnSectorBorder
|
|
||||||
* circle(r, outerRadius, 2.0) * borderColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
COLOR = col;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user