prgpu 0.1.13

GPU-accelerated rendering utilities for Adobe Premiere Pro and After Effects plugins
import vekl;

// Blackbody-inspired heatmap: encodes per-pixel max channel error as a
// thermal gradient controlled by a smoothstep.
//
//   black  → dark blue → bright blue → orange → white
//   (cold)                                        (hot)
//
// `smoothA` / `smoothB` let the user pick where the sigmoid ramp lives:
// below smoothA is black, above smoothB is white, between is the gradient.
//
// Tolerance fields still gate the pass/fail count used by metrics.

struct DiffParams
{
    float tolR;
    float tolG;
    float tolB;
    float tolA;
    float smoothA;
    float smoothB;
    uint _pad0;
    uint _pad1;
};

float3 error_to_color(float maxErr, float a, float b)
{
    float t = smoothstep(a, b, maxErr);

    // Blackbody-inspired piecewise ramp:
    //   0.00 → 0.25 : black → dark blue
    //   0.25 → 0.50 : dark blue → bright blue
    //   0.50 → 0.75 : bright blue → orange
    //   0.75 → 1.00 : orange → white
    float3 c;
    if (t < 0.25)
    {
        float s = t * 4.0;
        c = lerp(float3(0.0, 0.0, 0.0), float3(0.0, 0.0, 0.4), s);
    }
    else if (t < 0.5)
    {
        float s = (t - 0.25) * 4.0;
        c = lerp(float3(0.0, 0.0, 0.4), float3(0.1, 0.2, 1.0), s);
    }
    else if (t < 0.75)
    {
        float s = (t - 0.5) * 4.0;
        c = lerp(float3(0.1, 0.2, 1.0), float3(1.0, 0.5, 0.0), s);
    }
    else
    {
        float s = (t - 0.75) * 4.0;
        c = lerp(float3(1.0, 0.5, 0.0), float3(1.0, 1.0, 1.0), s);
    }
    return c;
}

[shader("compute")]
[numthreads(16, 16, 1)]
void diff(
    uint3 threadId : SV_DispatchThreadID,
    StructuredBuffer<uint> outgoing,
    StructuredBuffer<uint> incoming,
    RWStructuredBuffer<uint> dst,
    ConstantBuffer<FrameParams> frame,
    ConstantBuffer<DiffParams> params)
{
    TextureView rendered  = TextureView(outgoing, frame.outDesc);
    TextureView reference = TextureView(incoming, frame.inDesc);
    RWTextureView output  = RWTextureView(dst, frame.dstDesc);

    uint2 size = output.Size(0u);
    if (threadId.x >= size.x || threadId.y >= size.y)
        return;

    float4 a = rendered.Load(threadId.xy, 0u);
    float4 b = reference.Load(threadId.xy, 0u);

    float4 diff = abs(a - b);
    float maxErr = max(max(diff.r, diff.g), max(diff.b, diff.a));

    output.Store(threadId.xy, float4(error_to_color(maxErr, params.smoothA, params.smoothB), 1.0));
}