64 lines
1.3 KiB
Go
64 lines
1.3 KiB
Go
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)
|
|
}
|