#ifndef MODERNPSX_VOXEL_LIGHT_BLEND_GLSL
#define MODERNPSX_VOXEL_LIGHT_BLEND_GLSL

float psxaVoxelLightMagnitude(vec3 color) {
    return max(max(color.r, color.g), color.b);
}

void psxaAccumulateVoxelLight(
    vec3 candidate,
    inout vec3 weightedChroma,
    inout float totalWeight,
    inout float strongestMagnitude
) {
    float magnitude = psxaVoxelLightMagnitude(candidate);
    if (magnitude <= 0.0001) return;

    // Squared weighting lets similarly strong sources mix while preventing a
    // large number of barely visible propagation tails from washing out the
    // nearest light's colour.
    float weight = magnitude * magnitude;
    // candidate already equals chroma * magnitude, so this is algebraically
    // the squared-weighted chroma without a division inside every tap.
    weightedChroma += candidate * magnitude;
    totalWeight += weight;
    strongestMagnitude = max(strongestMagnitude, magnitude);
}

vec3 psxaResolveVoxelLight(
    vec3 weightedChroma,
    float totalWeight,
    float strongestMagnitude
) {
    if (totalWeight <= 0.000001 || strongestMagnitude <= 0.0001) {
        return vec3(0.0);
    }

    vec3 blendedChroma = weightedChroma / totalWeight;
    blendedChroma /= max(
        psxaVoxelLightMagnitude(blendedChroma),
        0.0001
    );

    // Hue accumulates, but energy remains tied to the strongest source. This
    // avoids winner-takes-all colour boundaries without making a dense lamp
    // cluster much brighter than Minecraft's scalar lightmap expects.
    return blendedChroma * strongestMagnitude;
}

#endif
