godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.17k stars 98 forks source link

Increase the limit to Corner Radius of StyleBoxes, Provide Rounded option #11006

Closed donovani closed 1 month ago

donovani commented 1 month ago

Describe the project you are working on

A 2.5D party game with clean, geometric UI.

Describe the problem or limitation you are having in your project

I've been trying to make a clean UI that uses StyleBoxes to render as crisp as possible. This includes circles and anything masked to a circle. However it seems that there's a fundamental limit to how big of a circle you can make - 1024px. This is enforced as the max value, and as a result means that a Control node expanded to larger screen sizes would eventually go from being a circle to a rounded rectangle. Naturally, if there needs to be visuals oriented around that circle, you can imagine it would start to look ugly.

To me that limit seems relatively arbitrary. I'm also not thrilled at the idea of larger circles needing to be textures - requiring a high resolution image to avoid pixelation.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

I think there's a couple possible options:

  1. Allow users to set an arbitrarily high value (up to the maximum float value or something).
  2. Set a higher limit and also add a flag to round it regardless of the size, so that you can render a circle at all sizes.
  3. Implement relative units for corner radius values to make it independent of pixels (eg: %, vh, vw).

To me it doesn't matter. I'd prefer there be no limit, so that it can act similar to CSS's border-radius, but if there's a technical reason for needing a limit, then it would be good to have a workaround.

To that end, it might also make sense to slightly increase the Corner Detail limit as well, so that at big sizes, the geometry is less visible.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Depending on the option above:

  1. When you set a StyleBox's Corner Radius on any corner, it will not clamp the value to 1024. A user could add a number like 9999999 and the corner would be fully rounded up until 10 million pixels. It will still become a rounded rectangle as it surpasses that size, but it would be at the developer's discretion what that number is.
  2. There would still be a cap, but it would be higher than 1024 - if we're doing powers of 2 maybe 8192/16384. In addition there would be a boolean field named Rounded. If Rounded = true, then Corner Radius values will be ignored, and instead round the edges the maximum amount (a square would be a circle, a rectangle would be a capsule). Since there would be a guarantee the ends are perfectly rounded, this could potentially be rendered in a more efficient way (pure conjecture).
  3. Relative units would likely be the largest lift, as it would need components and rendering logic to be updated. Depending on implementation it could also be a breaking change. If I had to determine an approach, I would add an extra enum alongside each value such that a user would specify. By default, the units would be pixels.
// Example for option 1
styleBoxFlat.CornerRadiusBottomLeft = 9876543210;

// Example for option 2
styleBoxFlat.Rounded = true;

// Example for option 3
styleBoxFlat.CornerRadiusBottomLeft = 100;
styleBoxFlat.CorderRadiusBottomLeftUnit = CornerRadiusUnit.PERCENT;

If this enhancement will not be used often, can it be worked around with a few lines of script?

Yes. A user could still make UIs in the exact same way. This is purely adding more flexibility to existing systems. Additionally, if a Rounded option is made available, then users are free to ignore it and continue working as they have been.

If option 3 is chosen and relative units are introduced, the implementation could be breaking. If units are a separate variable from the magnitude of the vector, then having the units default to pixels would simplify migration.

Is there a reason why this should be core and not an add-on in the asset library?

This is part of Godot's UI system and likely touches on it's rendering. This is a change that would enable developers to build even better/cleaners UIs with the core systems the engine already provides.

Lielay9 commented 1 month ago

I may have misunderstood but if your goal is to draw circles, it is not too difficult to extend the StyleBox-class. e.g.

@tool
extends StyleBox
class_name StyleBoxCircle

@export var color: Color = Color.WHITE:
    set(value):
        color = value
        emit_changed()
@export var antialiased: bool = false:
    set(value):
        antialiased = value
        emit_changed()

func _draw(to_canvas_item: RID, rect: Rect2) -> void:
    var radius: float = minf(rect.size.x, rect.size.y) / 2.0
    if antialiased:
        radius -= 0.5 # Feather juts out a little without. (0.5 the feather is in about the middle).
    RenderingServer.canvas_item_add_circle(to_canvas_item, rect.get_center(), radius, color, antialiased)

That said I guess the StyleBoxFlat corner size could use 'or_greater' to allow higher values.

donovani commented 1 month ago

You've understood my goal correctly. I think you're right that an extended style box could allow for a larger corner radius without the need for a texture. I appreciate that solution and might incorporate that into my project in the meantime.

That said, I think it'd still be nice for the out-of-the-box StyleBoxFlat to support a larger corner radius. It's an improvement that could be used by the whole community and isn't really specific to my game. Godot also doesn't have the concept of relative units like CSS does (%, vw, vh, vmax, vmin), which means that common screen-independent workarounds that work for web are not possible here. So from my perspective, the best way to achieve that is by increasing the corner radius limit

Calinou commented 1 month ago

People often use border-radius: 9999px in CSS (which is not the same as border-radius: 50% for non-square shapes), so I would just increase the property range maximum in the inspector using or_greater.

Note that you can already set a higher value on the StyleBoxFlat resource using a script.