/// <summary> /// Get a ColorStop on the left of pos, and on the right of pos. /// Third tuple member is true when no stop was found that actually /// matches pos /// </summary> /// <param name="pos"></param> /// <returns></returns> public LeftRightFound GetLeftRight(float pos) { var needle = new ColorStop { Position = pos }; ColorStop l = null; ColorStop r = null; var idx = Stops.BinarySearch(needle); var notfound = false; if (idx < 0) { idx = ~idx; } if (idx == Stops.Count) // there was no item larger than needle { notfound = true; // get the last two stops, or just last one if possible. r = new ColorStop(Stops[idx - 1]); if ((idx - 2) >= 0) { l = new ColorStop(Stops[idx - 2]); } else { // if there was only one stop we copy r to l, then set r to be on position 1.0f // so we can still interpolate l = new ColorStop(r); r.Position = 1.0f; } } else { // idx is the either precisely pos or the one right after. r = new ColorStop(Stops[idx]); // try to get the stop on the left of pos if ((idx - 1) >= 0) { l = new ColorStop(Stops[idx - 1]); } else { // or copy the one from the right, l = new ColorStop(r); // but set its position to 0.0f so we can // still interpolate l.Position = 0.0f; } } // done, give it back. return(new LeftRightFound(l, r, notfound)); }
/// <summary> /// Add given ColorStop /// </summary> /// <param name="cstop"></param> public void InsertColorStop(ColorStop cstop) { if (Stops.Count == 0) { Stops.Add(cstop); return; } var idx = Stops.BinarySearch(cstop); if (idx < 0) { idx = ~idx; } if (idx == Stops.Count) { Stops.Add(cstop); } else { Stops.Insert(idx, cstop); } }
/// <summary> /// Evaluate pos into a color /// </summary> /// <param name="pos">Value in range 0.0f-1.0f</param> /// <param name="color">Color will be interpolated into this</param> /// <returns></returns> public void evaluate(float pos, float4 color) { if (Stops.Count == 0) { color.x = 0.0f; color.y = 0.0f; color.z = 0.0f; color.w = 0.0f; return; } // stop1 = left of pos var left = Stops[0]; // stop2 = right of pos ColorStop right = null; // if there is only one stop, or we're on the left of the very first stop // just copy the color, we're done. if (Stops.Count == 1 || pos <= left.Position) { color.Copy(left.Color); } else { // get left and right items var lr = GetLeftRight(pos); left = lr.Item1; right = lr.Item2; var last_item = lr.Item3; // if we're on the right of the right stop, copy // color, we're done. if (pos >= right.Position) { color.Copy(right.Color); } else { // if we're on constant interpolation, lets use // color on left of position. if (Interpolation == Interpolations.Constant) { color.Copy(left.Color); } else { // ok, so we need to interpolate float mfac; float fac; // get factor if (Math.Abs(left.Position - right.Position) > 0.0001) { fac = Math.Abs(pos - right.Position) / Math.Abs(left.Position - right.Position); } else { fac = last_item ? 1.0f : 0.0f; } // extra easing if ease if (Interpolation == Interpolations.Ease) { mfac = fac * fac; fac = 3.0f * mfac - 2.0f * mfac * fac; } // right color fac mfac = 1.0f - fac; // factor colors left.Color *= fac; right.Color *= mfac; // add factored colors to get new interpolated color var interpolated_color = left.Color + right.Color; // copy, done color.Copy(interpolated_color); } } } }