diff --git a/Content.Client/UserInterface/Controls/RadialContainer.cs b/Content.Client/UserInterface/Controls/RadialContainer.cs index 0efa51f63d..72555aab5f 100644 --- a/Content.Client/UserInterface/Controls/RadialContainer.cs +++ b/Content.Client/UserInterface/Controls/RadialContainer.cs @@ -1,23 +1,12 @@ using Robust.Client.UserInterface.Controls; using System.Linq; using System.Numerics; -using Robust.Client.Graphics; -using Robust.Shared.Prototypes; namespace Content.Client.UserInterface.Controls; [Virtual] 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]; - /// /// Increment of radius per child element to be rendered. /// @@ -35,7 +24,11 @@ public class RadialContainer : LayoutContainer [ViewVariables(VVAccess.ReadWrite)] public Vector2 AngularRange { - get => _angularRange; + get + { + return _angularRange; + } + set { var x = value.X; @@ -96,9 +89,7 @@ public class RadialContainer : LayoutContainer /// public RadialContainer() { - IoCManager.InjectDependencies(this); - _shader = _prototypeManager.Index("RadialMenu") - .InstanceUnique(); + } /// @@ -170,67 +161,6 @@ public class RadialContainer : LayoutContainer return base.ArrangeOverride(finalSize); } - /// - 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); - } - /// /// Specifies the different radial alignment modes /// diff --git a/Content.Client/UserInterface/Controls/RadialMenu.cs b/Content.Client/UserInterface/Controls/RadialMenu.cs index 35aa655f3e..9734cf2960 100644 --- a/Content.Client/UserInterface/Controls/RadialMenu.cs +++ b/Content.Client/UserInterface/Controls/RadialMenu.cs @@ -362,12 +362,12 @@ public interface IRadialMenuItemWithSector /// /// Angle in radian where button sector should start. /// - public float AngleSectorFrom { set; get; } + public float AngleSectorFrom { set; } /// /// Angle in radian where button sector should end. /// - public float AngleSectorTo { set; get; } + public float AngleSectorTo { set; } /// /// Outer radius for drawing segment and pointer detection. @@ -388,41 +388,6 @@ public interface IRadialMenuItemWithSector /// Coordinates of center in parent component - button container. /// public Vector2 ParentCenter { set; } - - /// - /// Marker, is menu item hovered currently. - /// - public bool IsHovered { get; } - - /// - /// Color for menu item background when it is hovered over. - /// - Color HoverBackgroundColor { get; } - - /// - /// Color for menu item default state. - /// - Color BackgroundColor { get; } - - /// - /// Color for menu item border when item is hovered over. - /// - Color HoverBorderColor { get; } - - /// - /// Color for menu item border default state. - /// - Color BorderColor { get; } - - /// - /// Marker, if menu item background should be drawn. - /// - public bool DrawBackground { get; } - - /// - /// Marker, if menu item borders should be drawn. - /// - public bool DrawBorder { get; } } [Virtual] @@ -448,7 +413,7 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia /// Marker, that controls if border of segment should be rendered. Is false by default. /// /// - /// Default color of border is same as color of background. Use + /// By default color of border is same as color of background. Use /// and to change it. /// public bool DrawBorder { get; set; } = false; @@ -494,6 +459,12 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia set => _hoverBorderColorSrgb = Color.ToSrgb(value); } + /// + /// Color of separator lines. + /// Separator lines are used to visually separate sector of radial menu items. + /// + public Color SeparatorColor { get; set; } = new Color(128, 128, 128, 128); + /// float IRadialMenuItemWithSector.AngleSectorFrom { @@ -502,7 +473,6 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia _angleSectorFrom = value; _isWholeCircle = IsWholeCircle(value, _angleSectorTo); } - get => _angleSectorFrom; } /// @@ -513,7 +483,6 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia _angleSectorTo = value; _isWholeCircle = IsWholeCircle(_angleSectorFrom, value); } - get => _angleSectorTo; } /// @@ -535,6 +504,44 @@ public class RadialMenuTextureButtonWithSector : RadialMenuTextureButton, IRadia { } + /// + 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); + } + } + /// protected override bool HasPoint(Vector2 point) { diff --git a/Content.Client/UserInterface/Controls/SimpleRadialMenu.xaml.cs b/Content.Client/UserInterface/Controls/SimpleRadialMenu.xaml.cs index 589a97629d..15c8065a44 100644 --- a/Content.Client/UserInterface/Controls/SimpleRadialMenu.xaml.cs +++ b/Content.Client/UserInterface/Controls/SimpleRadialMenu.xaml.cs @@ -7,7 +7,6 @@ using Robust.Client.GameObjects; using Robust.Shared.Timing; using Robust.Client.UserInterface.XAML; using Robust.Client.Input; -using Robust.Shared.Collections; namespace Content.Client.UserInterface.Controls; @@ -174,7 +173,7 @@ public partial class SimpleRadialMenu : RadialMenu private void ClearExistingChildrenRadialButtons() { - var toRemove = new ValueList(ChildCount); + var toRemove = new List(ChildCount); foreach (var child in Children) { if (child != ContextualButton && child != MenuOuterAreaButton) diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml index 631b8ee920..6e0bbd55b4 100644 --- a/Resources/Prototypes/Shaders/shaders.yml +++ b/Resources/Prototypes/Shaders/shaders.yml @@ -108,9 +108,4 @@ - type: shader id: Hologram kind: source - path: "/Textures/Shaders/hologram.swsl" - -- type: shader - id: RadialMenu - kind: source - path: "/Textures/Shaders/radial-menu.swsl" + path: "/Textures/Shaders/hologram.swsl" \ No newline at end of file diff --git a/Resources/Textures/Shaders/radial-menu.swsl b/Resources/Textures/Shaders/radial-menu.swsl deleted file mode 100644 index 30fa1a4cba..0000000000 --- a/Resources/Textures/Shaders/radial-menu.swsl +++ /dev/null @@ -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; -}