Zum Inhalt

apple/PhysarumApp/Sources/Model/PresetMorph.swift

import simd
import PhysarumEngine

/// HSV (each 0…1) → engine RGB.
func hsv2rgb(_ h: Double, _ s: Double, _ v: Double) -> RGB {
    let i = Int(h * 6) % 6
    let f = h * 6 - Double(Int(h * 6))
    let p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s)
    let c: (Double, Double, Double)
    switch i {
    case 0: c = (v, t, p)
    case 1: c = (q, v, p)
    case 2: c = (p, v, t)
    case 3: c = (p, q, v)
    case 4: c = (t, p, v)
    default: c = (v, p, q)
    }
    return RGB(Float(c.0), Float(c.1), Float(c.2))
}

/// Component-wise linear interpolation of two RGB colors.
func mixRGB(_ a: RGB, _ b: RGB, _ t: Double) -> RGB {
    a + (b - a) * Float(t)
}

/// Interpolate two presets at t∈[0,1]. Scalars (incl. matrix, agentCount) lerp via
/// the registry; colors lerp component-wise; discrete enums switch at the 0.5
/// threshold. Endpoints are exact (t≤0 → a, t≥1 → b).
func morphParams(_ a: PresetParams, _ b: PresetParams, t: Double) -> PresetParams {
    if t <= 0 { return a }
    if t >= 1 { return b }
    var out = a
    for d in ParamRegistry.all {
        let va = d.get(a), vb = d.get(b)
        d.set(&out, va + (vb - va) * t)     // set() rounds ints
    }
    for i in 0..<3 {
        out.species[i].color = mixRGB(a.species[i].color, b.species[i].color, t)
    }
    out.backgroundColor = mixRGB(a.backgroundColor, b.backgroundColor, t)
    out.spawnPattern = t < 0.5 ? a.spawnPattern : b.spawnPattern
    out.blendMode = t < 0.5 ? a.blendMode : b.blendMode
    return out
}