// TruVisuals - CRT Grain
// Subtle, keyframeable fine FILM GRAIN filter for DaVinci Resolve (Studio).
// Per-pixel monochrome luminance noise, reseeded every frame so it dances like
// real film grain. Amplitude is gently tapered toward black/white so highlights
// don't get noisy and pure shadows stay cleaner. 'Size' quantizes the sampling
// grid so the grain can be coarsened into larger clumps.
// Per-pixel effect: uses the plain (p_R,p_G,p_B) transform signature.

DEFINE_UI_PARAMS(amount, Amount,       DCTLUI_SLIDER_FLOAT, 0.30, 0.0, 1.0, 0.01)
DEFINE_UI_PARAMS(grainSize, Size px, DCTLUI_SLIDER_FLOAT, 1.0,  1.0, 8.0, 0.5)

// Look constants (match the numpy preview exactly).
#define MAX_AMP   0.16f   // grain amplitude at Amount = 1.0
#define LUMA_MOD  0.55f   // how much the mid-tone bias tapers grain at black/white

__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
{
    // --- Size: quantize coordinates into blocks; one random value per block ---
    float size = _fmaxf(grainSize, 1.0f);
    int bx = (int)_floorf((float)p_X / size);
    int by = (int)_floorf((float)p_Y / size);

    // Per-block, per-frame seed. blockY*Width + blockX is unique across the
    // frame (blockX < Width); the frame term reshuffles it every frame.
    unsigned int seed = (unsigned int)(TIMELINE_FRAME_INDEX * p_Width * p_Height
                                       + by * p_Width + bx);

    // Uniform noise in [0,1) -> signed noise in [-1,1).
    float n = RAND(seed) * 2.0f - 1.0f;

    // --- Monochrome luminance response ---
    float lum = 0.299f * p_R + 0.587f * p_G + 0.114f * p_B;
    float d = 2.0f * lum - 1.0f;
    float resp = 1.0f - LUMA_MOD * d * d;   // 1.0 at mid -> (1-LUMA_MOD) at extremes

    // --- Apply identical monochrome grain to all three channels ---
    float delta = n * (amount * MAX_AMP) * resp;

    float r = _saturatef(p_R + delta);
    float g = _saturatef(p_G + delta);
    float b = _saturatef(p_B + delta);

    return make_float3(r, g, b);
}
