Color Interpolation
The easiest form of interpolation is linear interpolation by using the function \(\text{linpol}(p,a,b) := a \cdot (1 - p) + b \cdot p\) where \(a\) is 'from' and \(b\) is to and \(0.0 \leq p \leq 1.0\), meaning if \(p = 0.0\) then \(\text{linpol}(p,a,b) = a\) and if \(p = 1.0\) then \(\text{linpol}(p,a,b) = b\). If we want to interpolate RGB colors we interpolate each channel seperately:
$$\text{linpol}(p,\{r_{0},g_{0},b_{0}\},\{r_{1},g_{1},b_{1}\} := \{\\r_{0} \cdot (1 - p) + r_{1} \cdot p, \\ g_{0} \cdot (1 - p) + g_{1} \cdot p, \\ b_{0} \cdot (1 - p) + b_{1} \cdot p\\\}$$If we want to interpolate between more colors we do it in steps. Interpolating between color 1 and color 2, color 2 and color 3, ... and so forth. We divide \(0..1\) into intervals of size \(s\) and calculate in which interval \(p\) falls into and then interpolate between the corresponding colors. For example with three colors we interpolate between color 1 and color 2 for \(0.0 \leq p \leq 0.5\) and between color 2 and color 3 for \(0.5 \leq p \leq 1.0\). With this knowledge we can create color gradients.
The algorithm
proc linpol(f64 p, color a, color b) color
begin
color c := (0.0, 0.0, 0.0)
c[0] = a[0] * (1 - p) + b[0] * p
c[1] = a[1] * (1 - p) + b[1] * p
c[2] = a[2] * (1 - p) + b[2] * p
return c
end
proc linpol_n(f64 p, color[] colors) color
begin
f64 step_size := 1.0 / f64(size(colors) - 1)
u32 color_index := u32(floor(p / step_size))
; shift p to 0..step_size
f64 pi = p - (step_size * f64(color_index))
; scale 0..step_size to 0..1
pi /= step_size
; color for pi ~= 0.0
color a := colors[color_index]
; color for pi ~= 1.0
; in the edge case of p = 1.0 color_index points to the last color
; so color_index+1 would be invalid.
color b := colors[min(size(colors)-1, color_index+1)]
return linpol(pi, a, b)
end