/***********************************************/
/*           Copyright (c) 2025 Belmu          */
/*             All Rights Reserved             */
/***********************************************/

/*
    [Credits]:
        Jessie - providing beam ratio equation for transmission (https://github.com/Jessie-LC)

    [References]:
        Arnott, W.P. (2008). Fresnel equations. https://www.patarnott.com/atms749/pdf/FresnelEquations.pdf
        Lagarde, S. (2013). Memo on Fresnel equations. https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/
        Wikipedia. (2023). Snell's law. https://en.wikipedia.org/wiki/Snell%27s_law

    [Notes]:
        These two equations both assume a non-polarized input.
        I modified Snell's law to get the angle of refraction, I don't like calling it "Snell's law" because it was first
        discovered by a Persian scientist called Ibn-Sahl.
*/

complexFloat calculateRefractedAngle(complexFloat thetaI, complexFloat nI, complexFloat nT) {
    return complexArcSin(complexMul(complexDiv(nI, nT), complexSin(thetaI)));
}

complexFloat reflectionSenkrecht(complexFloat cosThetaI, complexFloat cosThetaT, complexFloat nI, complexFloat nT) {
    complexFloat nICosThetaI = complexMul(nI, cosThetaI);
    complexFloat nTCosThetaT = complexMul(nT, cosThetaT);
    return complexDiv(complexSub(nICosThetaI, nTCosThetaT), complexAdd(nICosThetaI, nTCosThetaT));
}

complexFloat reflectionParallel(complexFloat cosThetaI, complexFloat cosThetaT, complexFloat nI, complexFloat nT) {
    complexFloat nICosThetaT = complexMul(nI, cosThetaT);
    complexFloat nTCosThetaI = complexMul(nT, cosThetaI);
    return complexDiv(complexSub(nTCosThetaI, nICosThetaT), complexAdd(nTCosThetaI, nICosThetaT));
}

complexFloat transmissionSenkrecht(complexFloat cosThetaI, complexFloat cosThetaT, complexFloat nI, complexFloat nT) {
    complexFloat numerator = complexMul(2.0, complexMul(nI, cosThetaI));
    return complexDiv(numerator, complexAdd(complexMul(nI, cosThetaI), complexMul(nT, cosThetaT)));
}

complexFloat transmissionParallel(complexFloat cosThetaI, complexFloat cosThetaT, complexFloat nI, complexFloat nT) {
    complexFloat numerator = complexMul(2.0, complexMul(nI, cosThetaI));
    return complexDiv(numerator, complexAdd(complexMul(nI, cosThetaT), complexMul(nT, cosThetaI)));
}

float fresnelComplex_R(float cosThetaI_real, complexFloat n1, complexFloat n2) {
    complexFloat thetaI = complexFloat(acos(cosThetaI_real), 0.0);
    complexFloat thetaT = calculateRefractedAngle(thetaI, n1, n2);

    complexFloat cosThetaI = complexCos(thetaI);
    complexFloat cosThetaT = complexCos(thetaT);

    float Rs = complexAbs(reflectionSenkrecht(cosThetaI, cosThetaT, n1, n2));
    float Rp = complexAbs(reflectionParallel (cosThetaI, cosThetaT, n1, n2));

    return saturate((Rs * Rs + Rp * Rp) * 0.5);
}

float fresnelComplex_T(float cosThetaI_real, complexFloat n1, complexFloat n2) {
    complexFloat thetaI = complexFloat(acos(cosThetaI_real), 0.0);
    complexFloat thetaT = calculateRefractedAngle(thetaI, n1, n2);

    complexFloat cosThetaI = complexCos(thetaI);
    complexFloat cosThetaT = complexCos(thetaT);

    if (complexAbs(complexSin(thetaT)) > 1.0) return 0.0;

    float Ts = complexAbs(transmissionSenkrecht(cosThetaI, cosThetaT, n1, n2));
    float Tp = complexAbs(transmissionParallel (cosThetaI, cosThetaT, n1, n2));

    float beamRatio = complexAbs(complexDiv(complexMul(n2, cosThetaT), complexMul(n1, cosThetaI)));

    return saturate(beamRatio * (Ts * Ts + Tp * Tp) * 0.5);
}
