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

/*
    [References]:
        Wu et al. (2012). Rendering realistic spectral bokeh due to lens stops and aberrations. https://jiaze-wu.weebly.com/uploads/1/2/2/4/12248481/2013_vc_bokehrendering_jiazewu.pdf

    [Notes]:
        The sensor size is in decimeters.
*/

#define DOUBLE_GAUSS_0 0
#define DOUBLE_GAUSS_1 1
#define COOKE_TRIPLET  2
#define TESSAR         3
#define PETZVAL        4
#define FISHEYE        5
#define LEICA_SUMMILUX 6

const float bladeSectorAngle = TAU / APERTURE_BLADES;

float getAutoFocusDistance(vec3 sensorPosition, vec3 direction) {
    vec3 focalHit = raytraceVoxel(sensorPosition, direction, MAX_RAYTRACE_STEPS).position;

    return max0(distance(focalHit, sensorPosition));
}

#if LENS_TYPE == 0

    const float emptyCoefficients[6] = float[6](0.0, 0.0, 0.0, 0.0, 0.0, 0.0);

    const struct LensElement {
        float radius; // Radius of the circle primitive (if negative, element is concave)
        float thickness; // Distance to next element
        float aperture;  // Aperture radius of the element
        SellmeierCoefficients coefficients;
        bool isApertureStop;
        float asphericalCoefficients[6];
    };

    const float mm_2_m = 0.001; // millimeters to meters conversion

    const float diameter_2_radius = 0.5; // diameter to radius conversion
    
    #if LENS_MODEL == DOUBLE_GAUSS_0

        const LensElement lensSystem[] = LensElement[](
            LensElement( 085.50 * mm_2_m, 11.6 * mm_2_m, 76.0 * mm_2_m, N_LAF2, false, emptyCoefficients),
            LensElement( 408.33 * mm_2_m, 01.5 * mm_2_m, 76.0 * mm_2_m, N_AIR , false, emptyCoefficients),
            LensElement( 040.35 * mm_2_m, 17.0 * mm_2_m, 66.0 * mm_2_m, N_SSK5, false, emptyCoefficients),
            LensElement( 156.05 * mm_2_m, 03.5 * mm_2_m, 66.0 * mm_2_m, F2HT  , false, emptyCoefficients),
            LensElement( 025.05 * mm_2_m, 13.7 * mm_2_m, 44.0 * mm_2_m, N_AIR , false, emptyCoefficients),
            LensElement( 000.00 * mm_2_m, 08.3 * mm_2_m, 42.6 * mm_2_m, N_AIR , true , emptyCoefficients),
            LensElement(-036.80 * mm_2_m, 03.5 * mm_2_m, 44.0 * mm_2_m, N_SF8 , false, emptyCoefficients),
            LensElement( 055.00 * mm_2_m, 23.0 * mm_2_m, 52.0 * mm_2_m, N_LAF2, false, emptyCoefficients),
            LensElement(-051.50 * mm_2_m, 01.0 * mm_2_m, 52.0 * mm_2_m, N_AIR , false, emptyCoefficients),
            LensElement( 123.50 * mm_2_m, 17.0 * mm_2_m, 52.0 * mm_2_m, N_LAF2, false, emptyCoefficients),
            LensElement(-204.96 * mm_2_m, 00.0 * mm_2_m, 52.0 * mm_2_m, N_AIR , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.045);

    #elif LENS_MODEL == DOUBLE_GAUSS_1
        
        const LensElement lensSystem[] = LensElement[](
            LensElement( 075.050 * mm_2_m, 09.000 * mm_2_m, 33.0 * mm_2_m, S_LAM3 , false, emptyCoefficients),
            LensElement( 270.700 * mm_2_m, 00.100 * mm_2_m, 33.0 * mm_2_m, N_AIR  , false, emptyCoefficients),
            LensElement( 039.270 * mm_2_m, 16.510 * mm_2_m, 27.5 * mm_2_m, S_BAH11, false, emptyCoefficients),
            LensElement( 000.000 * mm_2_m, 02.000 * mm_2_m, 24.5 * mm_2_m, N_SF5  , false, emptyCoefficients),
            LensElement( 025.650 * mm_2_m, 10.990 * mm_2_m, 19.5 * mm_2_m, N_AIR  , false, emptyCoefficients),
            LensElement( 000.000 * mm_2_m, 13.000 * mm_2_m, 18.6 * mm_2_m, N_AIR  , true , emptyCoefficients),
            LensElement(-031.870 * mm_2_m, 07.030 * mm_2_m, 18.5 * mm_2_m, N_SF5  , false, emptyCoefficients),
            LensElement( 000.000 * mm_2_m, 08.980 * mm_2_m, 21.0 * mm_2_m, S_LAM3 , false, emptyCoefficients),
            LensElement(-043.510 * mm_2_m, 00.100 * mm_2_m, 21.0 * mm_2_m, N_AIR  , false, emptyCoefficients),
            LensElement( 221.140 * mm_2_m, 07.980 * mm_2_m, 23.0 * mm_2_m, S_BAH11, false, emptyCoefficients),
            LensElement(-088.790 * mm_2_m, 61.418 * mm_2_m, 23.0 * mm_2_m, N_AIR  , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.045);
    
    #elif LENS_MODEL == COOKE_TRIPLET

        const LensElement lensSystem[] = LensElement[](
            LensElement( 26.585199 * mm_2_m, 7.736537 * mm_2_m, 11.676172 * mm_2_m, N_LAK33B, false, emptyCoefficients),
            LensElement( 43.429037 * mm_2_m, 3.435887 * mm_2_m, 08.940243 * mm_2_m, N_AIR   , false, emptyCoefficients),
            LensElement(-55.415591 * mm_2_m, 3.999980 * mm_2_m, 07.469473 * mm_2_m, N_BASF2 , false, emptyCoefficients),
            LensElement( 29.198443 * mm_2_m, 2.127319 * mm_2_m, 06.034548 * mm_2_m, N_AIR   , false, emptyCoefficients),
            LensElement( 55.521418 * mm_2_m, 5.365190 * mm_2_m, 07.457009 * mm_2_m, N_LAK33B, false, emptyCoefficients),
            LensElement(-43.266572 * mm_2_m, 0.000000 * mm_2_m, 08.595248 * mm_2_m, N_AIR   , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.065);

    #elif LENS_MODEL == TESSAR

        const LensElement lensSystem[] = LensElement[](
            LensElement( 042.970 * mm_2_m, 09.800 * mm_2_m, 38.4 * mm_2_m * diameter_2_radius, N_LAK8, false, emptyCoefficients),
            LensElement(-115.330 * mm_2_m, 02.100 * mm_2_m, 38.4 * mm_2_m * diameter_2_radius, SF6   , false, emptyCoefficients),
            LensElement( 306.840 * mm_2_m, 04.160 * mm_2_m, 38.4 * mm_2_m * diameter_2_radius, N_AIR , false, emptyCoefficients),
            LensElement( 000.000 * mm_2_m, 04.000 * mm_2_m, 30.0 * mm_2_m * diameter_2_radius, N_AIR , true , emptyCoefficients),
            LensElement(-059.060 * mm_2_m, 01.870 * mm_2_m, 34.6 * mm_2_m * diameter_2_radius, SF6   , false, emptyCoefficients),
            LensElement( 040.930 * mm_2_m, 10.640 * mm_2_m, 34.6 * mm_2_m * diameter_2_radius, N_AIR , false, emptyCoefficients),
            LensElement( 183.920 * mm_2_m, 07.050 * mm_2_m, 33.0 * mm_2_m * diameter_2_radius, N_LAK8, false, emptyCoefficients),
            LensElement(-048.910 * mm_2_m, 00.000 * mm_2_m, 33.0 * mm_2_m * diameter_2_radius, N_AIR , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.045);

    #elif LENS_MODEL == PETZVAL

        const LensElement lensSystem[] = LensElement[](
            LensElement( 055.9 * mm_2_m, 05.2 * mm_2_m, 16.0 * mm_2_m, N_BK7HT, false, emptyCoefficients),
            LensElement(-043.7 * mm_2_m, 00.8 * mm_2_m, 16.0 * mm_2_m, LF7    , false, emptyCoefficients),
            LensElement( 460.4 * mm_2_m, 33.6 * mm_2_m, 16.0 * mm_2_m, N_AIR  , false, emptyCoefficients),
            LensElement( 110.6 * mm_2_m, 01.5 * mm_2_m, 16.0 * mm_2_m, LF7    , false, emptyCoefficients),
            LensElement( 038.9 * mm_2_m, 03.3 * mm_2_m, 16.0 * mm_2_m, N_AIR  , false, emptyCoefficients),
            LensElement( 048.0 * mm_2_m, 03.6 * mm_2_m, 16.0 * mm_2_m, N_BK7HT, false, emptyCoefficients),
            LensElement(-157.8 * mm_2_m, 30.0 * mm_2_m, 16.0 * mm_2_m, N_AIR  , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.042);

    #elif LENS_MODEL == FISHEYE
    
        const LensElement lensSystem[] = LensElement[](
            LensElement( 302.249 * mm_2_m, 008.335 * mm_2_m, 303.4 * mm_2_m * diameter_2_radius, N_F2    , false, emptyCoefficients),
            LensElement( 113.931 * mm_2_m, 074.136 * mm_2_m, 206.8 * mm_2_m * diameter_2_radius, N_AIR   , false, emptyCoefficients),
            LensElement( 752.019 * mm_2_m, 010.654 * mm_2_m, 178.0 * mm_2_m * diameter_2_radius, N_LAK21 , false, emptyCoefficients),
            LensElement( 083.349 * mm_2_m, 111.549 * mm_2_m, 134.2 * mm_2_m * diameter_2_radius, N_AIR   , false, emptyCoefficients),
            LensElement( 095.882 * mm_2_m, 020.054 * mm_2_m, 090.2 * mm_2_m * diameter_2_radius, N_SSK5  , false, emptyCoefficients),
            LensElement( 438.677 * mm_2_m, 053.895 * mm_2_m, 081.4 * mm_2_m * diameter_2_radius, N_AIR   , false, emptyCoefficients),
            LensElement( 000.000 * mm_2_m, 014.163 * mm_2_m, 060.8 * mm_2_m * diameter_2_radius, N_AIR   , true , emptyCoefficients),
            LensElement( 294.541 * mm_2_m, 021.934 * mm_2_m, 059.6 * mm_2_m * diameter_2_radius, N_BK7HT , false, emptyCoefficients),
            LensElement(-052.265 * mm_2_m, 009.714 * mm_2_m, 058.4 * mm_2_m * diameter_2_radius, SF6     , false, emptyCoefficients),
            LensElement(-142.884 * mm_2_m, 000.627 * mm_2_m, 059.6 * mm_2_m * diameter_2_radius, N_AIR   , false, emptyCoefficients),
            LensElement(-223.726 * mm_2_m, 009.400 * mm_2_m, 059.6 * mm_2_m * diameter_2_radius, N_KZFS11, false, emptyCoefficients),
            LensElement(-150.404 * mm_2_m, 000.000 * mm_2_m, 065.2 * mm_2_m * diameter_2_radius, N_AIR   , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.10);

    #elif LENS_MODEL == LEICA_SUMMILUX

        const LensElement lensSystem[] = LensElement[](
            LensElement(-110.114 * mm_2_m, 02.010 * mm_2_m, 40.0 * mm_2_m, N_BK7HT , false, emptyCoefficients),
            LensElement( 024.920 * mm_2_m, 07.400 * mm_2_m, 40.0 * mm_2_m, S_LAH65V, false, emptyCoefficients),
            LensElement(-305.000 * mm_2_m, 00.100 * mm_2_m, 40.0 * mm_2_m, N_AIR   , false, emptyCoefficients),
            LensElement( 028.346 * mm_2_m, 06.070 * mm_2_m, 40.0 * mm_2_m, S_LAH65V, false, float[6](0.3528e-1, -0.3903e-4, -0.3141e-6, 0.5132e-8, -0.6751e-10, 0.3015e-12)),
            LensElement(-057.560 * mm_2_m, 01.610 * mm_2_m, 40.0 * mm_2_m, N_SF64  , false, emptyCoefficients),
            LensElement( 016.624 * mm_2_m, 04.340 * mm_2_m, 40.0 * mm_2_m, N_AIR   , false, emptyCoefficients),
            LensElement( 000.000 * mm_2_m, 01.660 * mm_2_m, 40.5 * mm_2_m, N_AIR   , true , emptyCoefficients),
            LensElement(-197.204 * mm_2_m, 06.070 * mm_2_m, 40.0 * mm_2_m, N_BK7HT , false, emptyCoefficients),
            LensElement(-038.628 * mm_2_m, 01.500 * mm_2_m, 40.0 * mm_2_m, N_AIR   , false, emptyCoefficients),
            LensElement(-021.142 * mm_2_m, 01.720 * mm_2_m, 40.0 * mm_2_m, N_SF64  , false, emptyCoefficients),
            LensElement( 101.985 * mm_2_m, 05.860 * mm_2_m, 40.0 * mm_2_m, S_LAH65V, false, emptyCoefficients),
            LensElement(-021.905 * mm_2_m, 00.110 * mm_2_m, 40.0 * mm_2_m, N_AIR   , false, emptyCoefficients),
            LensElement( 060.026 * mm_2_m, 05.940 * mm_2_m, 40.0 * mm_2_m, S_LAH65V, false, float[6](0.1666e-1, -0.2344e-4, 0.3206e-7, 0.2056e-9, -0.5574e-11, 0.2373e-13)),
            LensElement(-031.325 * mm_2_m, 02.050 * mm_2_m, 40.0 * mm_2_m, N_SF64  , false, emptyCoefficients),
            LensElement( 031.325 * mm_2_m, 19.595 * mm_2_m, 40.0 * mm_2_m, N_AIR   , false, emptyCoefficients)
        );

        const vec2 sensorSize = vec2(0.042);

    #endif

    const int lensElementsCount = lensSystem.length();

    const LensElement rearLensElement = lensSystem[lensElementsCount - 1];

    float getFrontLensElementZ() {
        float opticalAxisZ = 0.0;

        for (int i = 0; i < lensElementsCount; i++)
            opticalAxisZ += lensSystem[i].thickness;
        
        return -opticalAxisZ;
    }

#else

    const vec2 sensorSize = vec2(0.22, 0.15); // Sensor size for a APS-C sensor

#endif
