migueldeicaza / SwiftGodot

New Godot bindings for Swift
https://migueldeicaza.github.io/SwiftGodotDocs/tutorials/swiftgodot-tutorials/
MIT License
1.06k stars 64 forks source link

experimental "Variant Leak Fixes" causing crashes in ArrayMesh.addSurfaceFromArrays #415

Open Airyzz opened 5 months ago

Airyzz commented 5 months ago

Recently upgrading my project to latest version of SwiftGodot, and encountered a crash in this function ArrayMesh.addSurfaceFromArrays.

Thankfully, enabling experimentalDisableVariantUnref does allow to workaround this for now! Here is the code causing the crash, as requested by the comment on that variable :)

import Foundation
import SwiftGodot

@Godot(.tool)
class Line3D: MeshInstance3D {
    var _vertices = PackedVector3Array()
    var _tangents = PackedVector3Array()
    var _colors = PackedColorArray()
    var _uvs = PackedVector2Array()
    var _indices = PackedInt32Array()

    var _arrays = GArray()

    var time: Float = 0

    @Export
    var width: Double = 1

    @Export
    var alpha: Double = 1

    @Export
    var useGlobalSpace: Bool = false

    @Export(.resourceType, "Gradient")
    var gradient: Gradient = .init()

    @Export(.resourceType, "Curve")
    var widthCurve: Curve = .init()

    @Export
    var points: PackedVector3Array = .init()

    override func _ready() {
        _arrays.resize(size: Mesh.ArrayType.max.rawValue)

        if mesh == nil {
            mesh = ArrayMesh()
        }

        if Engine.isEditorHint() == false {
            mesh = ArrayMesh()
        }

        rebuild()
    }

    override func _process(delta _: Double) {
        if Engine.isEditorHint() {
            rebuild()
        }
    }

    @Callable
    func rebuild() {
        printd("Rebuilding line!")
        guard let am = mesh as? ArrayMesh else {
            return
        }

        printd("Points: \(points)")

        am.clearSurfaces()

        var count = points.size()
        if count < 2 {
            return
        }

        _vertices.resize(newSize: count * 2)
        _tangents.resize(newSize: count * 2)
        _colors.resize(newSize: count * 2)
        _uvs.resize(newSize: count * 2)
        _indices.resize(newSize: count * 2)

        var invGlobalTx: Transform3D? = nil

        if useGlobalSpace {
            invGlobalTx = globalTransform.inverse()
        }

        var half_width = width / 2

        for i in 0 ..< Int(count) {
            var j0 = i * 2
            var j1 = j0 + 1

            var p = points[i]

            if invGlobalTx != nil {
                p = invGlobalTx! * p
            }

            _vertices[j0] = p
            _vertices[j1] = p

            var tangent: Vector3
            if i == 0 {
                tangent = (points[i + 1] - p).normalized()
            } else if i == count - 1 {
                tangent = (p - points[i - 1]).normalized()
            } else {
                tangent = (p - points[i - 1]).lerp(to: points[i + 1] - p, weight: 0.5).normalized()
            }

            _tangents[j0] = tangent
            _tangents[j1] = tangent

            var u = Double(i) / Double(count - 1)
            var c = gradient.sample(offset: u)
            c.alpha = Float(alpha)

            _colors[j0] = c
            _colors[j1] = c

            var v = half_width * widthCurve.sample(offset: u)

            _uvs[j0] = Vector2(x: Float(u), y: Float(-v))
            _uvs[j1] = Vector2(x: Float(u), y: Float(v))

            _indices[j0] = Int32(j0)
            _indices[j1] = Int32(j1)
        }

       // enable this to prevent crash!
       // experimentalDisableVariantUnref = true
        _arrays[Int(Mesh.ArrayType.vertex.rawValue)] = Variant(_vertices)
        _arrays[Int(Mesh.ArrayType.normal.rawValue)] = Variant(_tangents)
        _arrays[Int(Mesh.ArrayType.color.rawValue)] = Variant(_colors)
        _arrays[Int(Mesh.ArrayType.texUv.rawValue)] = Variant(_uvs)
        _arrays[Int(Mesh.ArrayType.index.rawValue)] = Variant(_indices)

        am.addSurfaceFromArrays(primitive: Mesh.PrimitiveType.triangleStrip, arrays: _arrays)
    }
}
migueldeicaza commented 1 month ago

Mhm, I am not able to reproduce this error