godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.97k stars 20.18k forks source link

Image.load_svg() breaks gradients bigger than ~2896.309 pixels when a scale argument is passed #86128

Closed MewPurPur closed 8 months ago

MewPurPur commented 9 months ago

Tested versions

The entire lifespan of Image.load_svg() functions, which were introduced in 4.2

System information

Godot v4.2.1.stable - Pop!_OS 22.04 LTS - X11 - GLES3 (Compatibility) - Mesa Intel(R) Graphics (ADL GT2) () - 12th Gen Intel(R) Core(TM) i5-1235U (12 Threads)

Issue description

When a SVG has a gradient bigger than 2896.309 units, any amount of scaling passed when it's loaded will break it. That is, if you upscale the SVG 10 times, you can't have gradients bigger than 289.6309 pixels for example. If you use such a gradient on a shape, it won't display.

Steps to reproduce

# A SVG of a red gradient on a circle over a white rectangle.
# One uses a 289.63px wide gradient, the other is a 289.64px wide gradient.
const gradient_on_svg := '<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><linearGradient x2="289.63" gradientUnits="userSpaceOnUse" id="a"><stop stop-color="red"/></linearGradient><rect width="16" height="16" fill="#fff"><circle r="16" fill="url(#a)"/></svg>'
const gradient_off_svg := '<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><linearGradient x2="289.64" gradientUnits="userSpaceOnUse" id="a"><stop stop-color="red"/></linearGradient><rect width="16" height="16" fill="#fff"><circle r="16" fill="url(#a)"/></svg>'
var gradient_on_texture: ImageTexture
var gradient_off_texture: ImageTexture

func _draw() -> void:
    draw_texture_rect(gradient_on_texture, Rect2(6, 40, 60, 60), false)
    draw_texture_rect(gradient_off_texture, Rect2(76, 40, 60, 60), false)

func _ready() -> void:
    var gradient_on := Image.new()
    var gradient_off := Image.new()
    gradient_on.load_svg_from_string(gradient_on_svg, 10.0)
    gradient_off.load_svg_from_string(gradient_off_svg, 10.0)
    gradient_on_texture = ImageTexture.create_from_image(gradient_on)
    gradient_off_texture = ImageTexture.create_from_image(gradient_off)
    queue_redraw()

Here's the result from this (ignore the background noise):

image

Minimal reproduction project (MRP)

No need to follow project files, just copy the above code inside a Node2D or a Control.

MewPurPur commented 9 months ago

The number is 2048 * sqrt(2)

lostminds commented 9 months ago

Looks like an issue with ThorVG, I just tried your svg code from above in their web viewer https://thorvg.github.io/thorvg.viewer/ and the gradient stops rendering at a certain size if you use the size slider to scale it up/down.

MewPurPur commented 9 months ago

Makes sense, I didn't know the upscaling was on their end. If this hasn't been reported there yet I'll do so in a bit.

MewPurPur commented 9 months ago

https://github.com/thorvg/thorvg/issues/1834