///|
/// Tone mapping and color space utilities.
/// Implements Reinhard, ACES, and filmic tone mapping operators.
pub fn reinhard_tone_map(color : Vec3) -> Vec3 {
let denom = {
x: color.x + 1.0,
y: color.y + 1.0,
z: color.z + 1.0,
}
{ x: color.x / denom.x, y: color.y / denom.y, z: color.z / denom.z }
}
pub fn aces_tone_map(color : Vec3) -> Vec3 {
let a = 2.51
let b = 0.03
let c = 2.43
let d = 0.59
let e = 0.14
let num_x = color.x * (color.x * a + b)
let den_x = color.x * (color.x * c + d) + e
let num_y = color.y * (color.y * a + b)
let den_y = color.y * (color.y * c + d) + e
let num_z = color.z * (color.z * a + b)
let den_z = color.z * (color.z * c + d) + e
{ x: (num_x / den_x).clamp(min=0.0, max=0.999),
y: (num_y / den_y).clamp(min=0.0, max=0.999),
z: (num_z / den_z).clamp(min=0.0, max=0.999) }
}
pub fn exposure_adjust(color : Vec3, exposure : Double) -> Vec3 {
let exp_factor = @math.pow(2.0, exposure)
color.mul_scalar(exp_factor)
}
pub fn gamma_correct(color : Vec3, gamma : Double) -> Vec3 {
{
x: @math.pow(color.x.max(0.0), 1.0 / gamma),
y: @math.pow(color.y.max(0.0), 1.0 / gamma),
z: @math.pow(color.z.max(0.0), 1.0 / gamma),
}
}
pub fn srgb_gamma_correct(color : Vec3) -> Vec3 {
let r = if color.x <= 0.0031308 {
color.x * 12.92
} else {
1.055 * @math.pow(color.x.max(0.0), 1.0 / 2.4) - 0.055
}
let g = if color.y <= 0.0031308 {
color.y * 12.92
} else {
1.055 * @math.pow(color.y.max(0.0), 1.0 / 2.4) - 0.055
}
let b = if color.z <= 0.0031308 {
color.z * 12.92
} else {
1.055 * @math.pow(color.z.max(0.0), 1.0 / 2.4) - 0.055
}
{ x: r.clamp(min=0.0, max=0.999), y: g.clamp(min=0.0, max=0.999), z: b.clamp(min=0.0, max=0.999) }
}