package helper import ( "math" ) // 0 if NaN or -Inf, 1 otherwise. func oneIfFinite(x float64) float64 { if x > math.Inf(-1) { return 1 } // NaN or -Inf return 0 } // x if >= 0, 0 otherwise (including NaN). func zeroOrMore(x float64) float64 { if x >= 0 { return x } return 0 } // the builtin max function doesn't ignore NaNs like I'd prefer, so do it ourselves. func max3(a, b, c float64) float64 { result := a if result != result || b > result { result = b } if result != result || c > result { result = c } return result } func ClampRGB(r, g, b float64) (_, _, _ float64) { // if any components are greater than 1, scale them down back into a legal range and // fade to white based to how for out of range they are. if m := max3(r, g, b); m > 1 { m2 := m * m if math.IsInf(m2, 1) { // This would be white if all components were sensible finite values, // although we will return zeros for any that were NaN or -Inf. return oneIfFinite(r), oneIfFinite(g), oneIfFinite(b) } c := 1 - 1/m r = c + r/m2 g = c + g/m2 b = c + b/m2 } // make sure no components are NaN or less than zero. // note that we do this last so that the fade to white logic has a chance to bring // components back into legal ranges. return zeroOrMore(r), zeroOrMore(g), zeroOrMore(b) }