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

bool isSphere(int id) {
    return id == SPHERE_0 || id == SPHERE_1;
}

bool isTranslucent(int id) {
    return id == SPHERE_1                 ||
           id == BLACK_STAINED_GLASS      ||
           id == BLUE_STAINED_GLASS       ||
           id == BROWN_STAINED_GLASS      ||
           id == CYAN_STAINED_GLASS       ||
           id == GLASS                    ||
           id == GRAY_STAINED_GLASS       ||
           id == GREEN_STAINED_GLASS      ||
           id == ICE                      ||
           id == LIGHT_BLUE_STAINED_GLASS ||
           id == LIGHT_GRAY_STAINED_GLASS ||
           id == LIME_STAINED_GLASS       ||
           id == MAGENTA_STAINED_GLASS    ||
           id == ORANGE_STAINED_GLASS     ||
           id == PINK_STAINED_GLASS       ||
           id == PURPLE_STAINED_GLASS     ||
           id == RED_STAINED_GLASS        ||
           id == TINTED_GLASS             ||
           id == WATER                    ||
           id == WHITE_STAINED_GLASS      ||
           id == YELLOW_STAINED_GLASS;
}

bool isGlass(int id) {
    return id == SPHERE_1                 ||
           id == BLACK_STAINED_GLASS      ||
           id == BLUE_STAINED_GLASS       ||
           id == BROWN_STAINED_GLASS      ||
           id == CYAN_STAINED_GLASS       ||
           id == GLASS                    ||
           id == GRAY_STAINED_GLASS       ||
           id == GREEN_STAINED_GLASS      ||
           id == LIGHT_BLUE_STAINED_GLASS ||
           id == LIGHT_GRAY_STAINED_GLASS ||
           id == LIME_STAINED_GLASS       ||
           id == MAGENTA_STAINED_GLASS    ||
           id == ORANGE_STAINED_GLASS     ||
           id == PINK_STAINED_GLASS       ||
           id == PURPLE_STAINED_GLASS     ||
           id == RED_STAINED_GLASS        ||
           id == TINTED_GLASS             ||
           id == WHITE_STAINED_GLASS      ||
           id == YELLOW_STAINED_GLASS;
}

bool isEmissive(int id) {
    return id == NETHER_PORTAL_AXIS_X       ||
           id == NETHER_PORTAL_AXIS_Z       ||
           id == GLOWSTONE                  ||
           id == JACK_O_LANTERN_EAST        ||
           id == JACK_O_LANTERN_NORTH       ||
           id == JACK_O_LANTERN_SOUTH       ||
           id == JACK_O_LANTERN_WEST        ||
           id == LANTERN_HANGING_FALSE      ||
           id == LANTERN_HANGING_TRUE       ||
           id == LAVA                       ||
           id == MAGMA_BLOCK                ||
           id == OCHRE_FROGLIGHT_X          ||
           id == OCHRE_FROGLIGHT_Y          ||
           id == OCHRE_FROGLIGHT_Z          ||
           id == PEARLESCENT_FROGLIGHT_X    ||
           id == PEARLESCENT_FROGLIGHT_Y    ||
           id == PEARLESCENT_FROGLIGHT_Z    ||
           id == SEA_LANTERN                ||
           id == SHROOMLIGHT                ||
           id == SOUL_LANTERN_HANGING_FALSE ||
           id == SOUL_LANTERN_HANGING_TRUE  ||
           id == SOUL_TORCH                 ||
           id == SOUL_WALL_TORCH_EAST       ||
           id == SOUL_WALL_TORCH_NORTH      ||
           id == SOUL_WALL_TORCH_SOUTH      ||
           id == SOUL_WALL_TORCH_WEST       ||
           id == TORCH                      ||
           id == VERDANT_FROGLIGHT_X        ||
           id == VERDANT_FROGLIGHT_Y        ||
           id == VERDANT_FROGLIGHT_Z        ||
           id == WALL_TORCH_EAST            ||
           id == WALL_TORCH_NORTH           ||
           id == WALL_TORCH_SOUTH           ||
           id == WALL_TORCH_WEST;
}

float computeBlocklightEmission(int id, float albedo, float wavelength) {
    switch (id) {
        case GLOWSTONE:
            return plancks(2300.0, wavelength) * 7e-2;
        case LAVA: case MAGMA_BLOCK:
            return plancks(1523.5, wavelength);
        case SEA_LANTERN:
            return plancks(4000.0, wavelength) * 1e-3;
        case LANTERN_HANGING_FALSE: case LANTERN_HANGING_TRUE: case TORCH: case WALL_TORCH_EAST: case WALL_TORCH_NORTH: case WALL_TORCH_SOUTH: case WALL_TORCH_WEST:
            return plancks(1900.0, wavelength);
        default: break;
    }
    return albedo;
}

const mat2x3 hardcodedMetals[] = mat2x3[](
    mat2x3(vec3(2.9114, 2.9497, 2.5845),    // Iron
        vec3(3.0893, 2.9318, 2.7670)),
    mat2x3(vec3(0.18299, 0.42108, 1.3734),  // Gold
        vec3(3.4242, 2.3459, 1.7704)),
    mat2x3(vec3(1.3456, 0.96521, 0.61722),  // Aluminum
        vec3(7.4746, 6.3995, 5.3031)),
    mat2x3(vec3(3.1071, 3.1812, 2.3230),    // Chrome
        vec3(3.3314, 3.3291, 3.1350)),
    mat2x3(vec3(0.27105, 0.67693, 1.3164),  // Copper
        vec3(3.6092, 2.6248, 2.2921)),
    mat2x3(vec3(1.9100, 1.8300, 1.4400),    // Lead
        vec3(3.5100, 3.4000, 3.1800)),
    mat2x3(vec3(2.3757, 2.0847, 1.8453),    // Platinum
        vec3(4.2655, 3.7153, 3.1365)),
    mat2x3(vec3(0.15943, 0.14512, 0.13547), // Silver
        vec3(3.9291, 3.1900, 2.3808))
);

mat2x3 getHardcodedMetal(Material material) {
    vec3 albedo = vec3(material.albedo);

    int metalID = int(material.F0 * 255.0 - 229.5);
    return metalID >= 0 && metalID < 8 ? hardcodedMetals[metalID] : mat2x3(f0ToIOR(albedo), vec3(0.0));
}
    
Material getMetalMaterial(float wavelength, vec3 normal, vec2 alpha) {
    Material metalMaterial = Material(
        0,
        0.0,
        1.0,
        normal,
        normal,
        normal,
        0.0,
        0.0,
        0.0,
        alpha,
        1.0,
        0.0,
        0.0,
        0.0
    );

    metalMaterial.N = srgbToSpectrum(hardcodedMetals[1][0], wavelength);
    metalMaterial.K = srgbToSpectrum(hardcodedMetals[1][1], wavelength);

    metalMaterial.F0 = iorToF0(metalMaterial.N);

    return metalMaterial;
}

Material getGlassMaterial(float wavelength, vec3 tint, vec3 normal, vec2 alpha) {
    Material glassMaterial = Material(
        0,
        srgbToSpectrum(tint, wavelength),
        0.0,
        normal,
        normal,
        normal,
        0.0,
        0.0,
        0.0,
        alpha,
        1.0,
        0.0,
        0.0,
        0.0
    );

    glassMaterial.N  = sellmeier(N_BK7HT, wavelength);
    glassMaterial.F0 = iorToF0(glassMaterial.N);

    return glassMaterial;
}

#if TONEMAP == ACES
    const vec3 waterAbsorptionCoefficients = (vec3(WATER_ABSORPTION_R, WATER_ABSORPTION_G, WATER_ABSORPTION_B) * 0.01) * SRGB_2_AP1_ALBEDO;
    const vec3 waterScatteringCoefficients = (vec3(WATER_SCATTERING_R, WATER_SCATTERING_G, WATER_SCATTERING_B) * 0.01) * SRGB_2_AP1_ALBEDO;
#else 
    const vec3 waterAbsorptionCoefficients = vec3(WATER_ABSORPTION_R, WATER_ABSORPTION_G, WATER_ABSORPTION_B) * 0.01;
    const vec3 waterScatteringCoefficients = vec3(WATER_SCATTERING_R, WATER_SCATTERING_G, WATER_SCATTERING_B) * 0.01;
#endif

Material getWaterMaterial(float wavelength, vec3 waveNormal, vec3 tangentNormal, vec3 geometricNormal) {
    Material waterMaterial = Material(
        0,
        srgbToSpectrum(exp(-waterAbsorptionCoefficients * 2.1), wavelength),
        0.0,
        waveNormal,
        tangentNormal,
        geometricNormal,
        1.333,
        0.0,
        0.0,
        vec2(1e-8),
        1.0,
        0.0,
        0.0,
        0.0
    );

    waterMaterial.N  = waterDispersion(wavelength);
    waterMaterial.F0 = iorToF0(waterMaterial.N);

    return waterMaterial;
}
