public float GetError(List <PaletteEntry> ramp) { var palette = this; var values = ramp .Select(x => palette.GetValue(x.Color)) .ToList(); // Show final error float error = 0; for (int i = 0; i < ramp.Count; i++) { int weight = ramp[i].Weight; var source = ramp[i].Color; var target = GetColor(values[i]); var vector = XnaHSL.BiconeDifference(source, target); float length = vector.LengthSquared(); error += length * weight; } int totalWeight = ramp.Select(x => x.Weight).Sum(); error /= totalWeight; return(error); }
public GeneratedColorPalette( PaletteGenerator generator, PaletteParameters parameters) { // Adjust base color up if black level is too close to it XnaHSL baseColor = AdjustBaseColor(parameters.BaseColor, generator.BlackLevel); // Tint just a little toward yellow based on yellow light XnaHSL untintedBaseColor = baseColor; if (baseColor.Saturation > 0) { baseColor = baseColor.LerpHue(60, parameters.YellowLight * 0.075f); } XnaHSL highlight, specular; GetHighlight(baseColor, generator, parameters, out highlight, out specular); XnaHSL shadow, darkest; GetShadow(untintedBaseColor, generator, parameters, out shadow, out darkest); // Set the calculated values BaseColor = baseColor; Darkest = darkest; Shadow = shadow; Highlight = highlight; Specular = specular; ReducedDepth = parameters.ReducedDepth; }
internal static IEnumerable <int> ColorLumaOrder(IEnumerable <Color> colors) { List <int> order = Enumerable .Range(0, colors.Count()) .Select(x => { Color color = colors.ElementAt(x); XnaHSL hsl = new XnaHSL(color); return(Tuple.Create(x, color, hsl)); }) // This actually needs to use luma instead of lightness, // because the perceptual order is important .OrderBy(x => GeneratedColorPalette.ValueFormula(x.Item2)) .ThenBy(x => x.Item3.Lightness) // If colors have the same lightness, // use the one with the least saturation .ThenBy(x => x.Item3.Saturation) // If colors have the same lightness, // use the one with the most alpha .ThenByDescending(x => x.Item2.A) .Select(x => x.Item1) .ToList(); return(order); }
private float SaturationMultiplier(GeneratedColorPalette rawPalette, PaletteRamp ramp, int index) { Color target = rawPalette.GetColor(ColorValues[index]); Color source = ramp.Colors[index]; XnaHSL targetHsl = new XnaHSL(target); XnaHSL sourceHsl = new XnaHSL(source); return(SaturationMultiplier(targetHsl, sourceHsl)); }
private static float SaturationMultiplier(XnaHSL targetHsl, XnaHSL sourceHsl) { if (targetHsl.Saturation < sourceHsl.Saturation && sourceHsl.Saturation > 0) { return(targetHsl.Saturation / sourceHsl.Saturation); } else { return(1f); } }
private static void GetHighlight( XnaHSL baseHSL, PaletteGenerator generator, PaletteParameters parameters, out XnaHSL highlight, out XnaHSL specular) { Color baseSpecular = PaletteGenerator.BaseSpecularColor(baseHSL.GetColor()); // Tint yellow XnaHSL specularHSL = new XnaHSL(baseSpecular); // If greyscale, simply treat the hue as yellow if (float.IsNaN(specularHSL.Hue)) { specularHSL = specularHSL.SetHue(60); } specularHSL = specularHSL.LerpHue(60, parameters.YellowLight); specularHSL = specularHSL.SetSaturation(MathHelper.Lerp( specularHSL.Saturation, 1f, parameters.YellowLight)); specularHSL = specularHSL.SetLightness(MathHelper.Lerp( specularHSL.Lightness, Math.Max(0.5f, specularHSL.Lightness), parameters.YellowLight)); // Add specular specularHSL = specularHSL.SetLightness(MathHelper.Lerp( specularHSL.Lightness, 1f, generator.Specularity)); // Reduce the lightness if the base color is darker than the generator color if (generator.BaseLightness > 0 && baseHSL.Lightness < generator.BaseLightness) { float lightnessDiff = generator.BaseLightness - baseHSL.Lightness; specularHSL = specularHSL.SetLightness(specularHSL.Lightness - (lightnessDiff)); } float highlightAmount = 0.5f; // If the base color is sufficiently bright, lighten the specular // to keep the contrast from getting too low float lightnessRatio = (baseHSL.Lightness - 0.5f) * 2f; if (lightnessRatio > 0) { specularHSL = specularHSL.SetLightness( MathHelper.Lerp(specularHSL.Lightness, 1f, lightnessRatio)); highlightAmount = MathHelper.Lerp(0.5f, 1f, lightnessRatio); } // Get highlight XnaHSL highlightHSL = XnaHSL.Lerp(baseHSL, specularHSL, highlightAmount); highlight = highlightHSL; specular = specularHSL; }
private static void GetShadow( XnaHSL baseHSL, PaletteGenerator generator, PaletteParameters parameters, out XnaHSL shadow, out XnaHSL darkest) { XnaHSL blackHSL = new XnaHSL( baseHSL.Hue, baseHSL.Saturation * generator.ShadowAmount, generator.BlackLevel, baseHSL.Alpha); // If the base color is sufficiently bright, lighten the darker shades float lightnessRatio = (baseHSL.Lightness - 0.5f) * 2f; if (lightnessRatio > 0) { blackHSL = blackHSL.SetSaturation(blackHSL.Saturation * (1f - lightnessRatio * 0.95f)); float blackLuma = Color_Util.GetLuma(blackHSL.GetColor()); // Increase the lightness by more if it's a color with a low // luma to lightness ratio float lumaRatio = 1f; if (blackLuma > 0) { lumaRatio = blackHSL.Lightness / blackLuma; } blackHSL = blackHSL.SetLightness( MathHelper.Lerp(blackHSL.Lightness, MathHelper.Lerp(blackHSL.Lightness, 1f, 0.25f), lightnessRatio * lumaRatio)); } // Tint black and shadow blue blackHSL = blackHSL.LerpHue(240, parameters.BlueShadow); blackHSL = blackHSL.SetSaturation(MathHelper.Lerp(blackHSL.Saturation, 1f, parameters.BlueShadow / 4f)); XnaHSL shadowHSL = XnaHSL.Lerp(blackHSL, baseHSL, generator.ShadowAmount); shadowHSL = shadowHSL.SetSaturation(MathHelper.Lerp(blackHSL.Saturation, baseHSL.Saturation, 0.5f)); shadowHSL = shadowHSL.SetHue(blackHSL.Hue); shadowHSL = shadowHSL.LerpHue(baseHSL.Hue, 0.25f); shadow = shadowHSL; darkest = blackHSL; }
public GeneratedColorPalette GetColorPalette(PaletteParameters parameters) { parameters = (PaletteParameters)parameters.Clone(); // Adjust the lightness of the base color XnaHSL baseHsl = new XnaHSL(this.BaseColor); XnaHSL parametersHsl = new XnaHSL(parameters.BaseColor); parametersHsl = parametersHsl.SetLightness( MathHelper.Lerp( parametersHsl.Lightness, baseHsl.Lightness, parameters.OriginalLightness)); parameters.BaseColor = parametersHsl.GetColor(); return(Ramp.Generator.GetPalette(parameters)); }
public Color GetColor(float value) { var ranges = GetRanges(); var start = ranges.First(); foreach (var end in ranges.Skip(1)) { if (value < end.Item2) { float range = end.Item2 - start.Item2; XnaHSL hsl = XnaHSL.Lerp(start.Item1, end.Item1, (value - start.Item2) / range); return(DepthColor(hsl.GetColor())); } start = end; } return(DepthColor(Specular.GetColor())); }
public static ColorVector ColorDifference(Color source, Color target, bool blueYellowRamp = false) { XnaHSL sourceHsl = new XnaHSL(source); XnaHSL targetHsl = new XnaHSL(target); float hue; if (float.IsNaN(sourceHsl.Hue) || float.IsNaN(targetHsl.Hue)) { hue = 0; } else { if (blueYellowRamp) { hue = GetBlueYellowHue(targetHsl.Hue) - GetBlueYellowHue(sourceHsl.Hue); } else { hue = targetHsl.Hue - sourceHsl.Hue; hue %= 360; if (hue <= -180) { hue += 360; } else if (hue > 180) { hue -= 360; } } } float sat = targetHsl.Saturation - sourceHsl.Saturation; float lit = targetHsl.Lightness - sourceHsl.Lightness; return(new ColorVector(hue, sat, lit, blueYellowRamp)); }
public XnaHSL GetHsl(float index) { PaletteEntry entry = Palette.GetEntry(Ramp.Colors.FirstOrDefault()); XnaHSL black = new XnaHSL(entry.Color); black = black.SetSaturation(0f); black = black.SetLightness(0f); entry = Palette.GetEntry(Ramp.Colors.LastOrDefault()); XnaHSL white = new XnaHSL(entry.Color); white = white.SetSaturation(0f); white = white.SetLightness(1f); XnaHSL left = black; XnaHSL right = white; for (int i = 0; i <= Ramp.Count; i++, index -= 1f, left = right) { if (i == Ramp.Count) { right = white; } else { entry = Palette.GetEntry(Ramp.GetColor(i)); right = new XnaHSL(entry.Color); } if (index <= 0f) { XnaHSL hslResult = XnaHSL.Lerp(left, right, (index + 1)); return(hslResult); } } return(right); }
public static Color operator +(Color color, ColorVector vector) { XnaHSL hsl = new XnaHSL(color) + vector; return(hsl.GetColor()); }
public static float ValueFormula(XnaHSL hsl) { return(ValueFormula(hsl.GetColor())); }