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;
        }
        public IndexedGeneratedPalette(
            SpriteRamp ramp,
            PaletteParameters parameters)
        {
            BasePalette = ramp.GetColorPalette(parameters);

            ColorValues        = ramp.ColorValues.ToArray();
            PaletteAdjustments = ramp.Adjustments.ToArray();

#if DEBUG
            System.Diagnostics.Debug.Assert(ramp.Count == ColorValues.Length, "Palette and ramp size must match");
            System.Diagnostics.Debug.Assert(ramp.Count == PaletteAdjustments.Length, "Palette and ramp size must match");
#endif

            // Saturation of the adjustment is reduced if the generated palette
            // is itself low saturation
            var rawParameters = (PaletteParameters)parameters.Clone();
            rawParameters.YellowLight = 0;
            rawParameters.BlueShadow  = 0;
            var rawPalette = ramp.GetColorPalette(rawParameters);

            AdjustmentsSaturationMultiplier = SaturationMultiplier(
                rawPalette.BaseColor, new XnaHSL(ramp.BaseColor));

            //@Debug: per color saturation adjustments

            /*AdjustmentsSaturationMultipliers = PaletteAdjustments
             *  .Select(x => 1f)
             *  .ToArray();
             * for (int i = 0; i < AdjustmentsSaturationMultipliers.Length; i++)
             * {
             *  AdjustmentsSaturationMultipliers[i] = SaturationMultiplier(
             *      rawPalette, ramp, i);
             * }*/
        }
예제 #3
0
        private void MinimizeSpecularityError(PaletteParameters parameters)
        {
            var entries = Palette.RampEntries(Ramp);

            Ramp.Generator.MinimizeSpecularityError(parameters, entries);
            RefreshAdjustments();
        }
예제 #4
0
        private float MinimizeError(
            PaletteParameters parameters,
            List <PaletteEntry> ramp,
            Range <float> range,
            Func <PaletteGenerator, float, float> function)
        {
            const int count      = 20;
            const int iterations = 3;

            List <Tuple <float, float> > errors = null;
            int index = -1;

            for (int i = 0; i < iterations; i++)
            {
                errors = Errors(parameters, ramp, range, count, function);
                float min = errors.Min(x => x.Item2);
                index = errors.FindIndex(x => x.Item2 == min);

                // Get the indices above and below the minimum value
                int step       = Math.Max(1, (int)(count * 0.3f) / 2);
                int startIndex = Math.Max(0, index - step);
                startIndex = Math.Min(count - step * 2, startIndex);
                int endIndex = startIndex + step * 2;
                range = new Range <float>(errors[startIndex].Item1, errors[endIndex].Item1);
            }
            return(errors[index].Item1);
        }
예제 #5
0
        private List <Tuple <float, float> > Errors(
            PaletteParameters parameters,
            List <PaletteEntry> ramp,
            Range <float> range,
            int count,
            Func <PaletteGenerator, float, float> function)
        {
            PaletteGenerator  copyGenerator  = (PaletteGenerator)Clone();
            PaletteParameters copyParameters = (PaletteParameters)parameters.Clone();
            float             interval       = (range.Maximum - range.Minimum) / count;

            var errors = new List <Tuple <float, float> >();

            for (int i = 0; i <= count; i++)
            {
                float value = range.Minimum + interval * i;
                function(copyGenerator, value);

                // Kind of necessary for user facing values
                // Minimize error on blue shadow
                copyParameters.MinimizeBlueError(copyGenerator, ramp);
                // Minimize error on yellow light
                copyParameters.MinimizeYellowError(copyGenerator, ramp);

                var   palette = copyGenerator.GetPalette(copyParameters);
                float error   = palette.GetError(ramp);
                errors.Add(Tuple.Create(value, error));
            }

            return(errors);
        }
예제 #6
0
        private void AdjustSpecularity(Color color, PaletteParameters parameters, float rawAmount)
        {
            // Find what this color's value looks like with minimum and maximum
            // specularity, and using where it should be inverse lerp into that
            // range
            var range = SpecularityRange();

            var darkGenerator = (PaletteGenerator)Clone();

            darkGenerator.Specularity = range.Minimum;
            var darkPalette = darkGenerator.GetPalette(parameters);

            var lightGenerator = (PaletteGenerator)Clone();

            lightGenerator.Specularity = range.Maximum;
            var lightPalette = lightGenerator.GetPalette(parameters);

            // Dark Base Value will be a larger number, because a dark color
            // will be closer to the specular
            float darkBaseValue  = darkPalette.GetValue(color);
            float lightBaseValue = lightPalette.GetValue(color);

            // I don't know how, but
            // Avoid divide by 0
            if (lightBaseValue == darkBaseValue)
            {
                this.Specularity = 1f;
                return;
            }

            float value = (rawAmount - lightBaseValue) / (darkBaseValue - lightBaseValue);

            this.Specularity = MathHelper.Lerp(range.Maximum, range.Minimum, value);
        }
예제 #7
0
        public override void CopyFrom(TactileDataContent other)
        {
            CheckSameClass(other);

            var source = (RecolorEntry)other;

            OtherNames = new List <string>(source.OtherNames);
            Parameters = (PaletteParameters)source.Parameters.Clone();
        }
예제 #8
0
        internal void MinimizeShadowError(PaletteParameters parameters, List <PaletteEntry> ramp)
        {
            var range = ShadowRange();
            Func <PaletteGenerator, float, float> function =
                (PaletteGenerator generator, float value) => generator.ShadowAmount = value;

            float minimum = MinimizeError(parameters, ramp, range, function);

            ShadowAmount = minimum;
        }
예제 #9
0
        internal void MinimizeSpecularityError(PaletteParameters parameters, List <PaletteEntry> ramp)
        {
            var range = SpecularityRange();
            Func <PaletteGenerator, float, float> function =
                (PaletteGenerator generator, float value) => generator.Specularity = value;

            float minimum = MinimizeError(parameters, ramp, range, function);

            Specularity = minimum;
        }
예제 #10
0
        public PaletteParameters DefaultParameters()
        {
            var parameters = new PaletteParameters(this.BaseColor);

            parameters.ReducedDepth = true;
            // Minimize error on blue shadow
            MinimizeBlueError(parameters);
            // Minimize error on yellow light
            MinimizeYellowError(parameters);

            return(parameters);
        }
        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;
        }
예제 #12
0
        public void AdjustValue(Color color, PaletteParameters parameters, float value)
        {
            var palette = GetPalette(parameters);

            if (palette.DarkerThanBase(color))
            {
                // Adjust shadow
                AdjustShadowAmount(color, palette, value);
            }
            else
            {
                // Adjust specular
                AdjustSpecularity(color, parameters, value);
            }
        }
        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;
        }
예제 #14
0
        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));
        }
예제 #15
0
        internal void RecalibrateError()
        {
            Ramp.Generator.BaseLightness = new XnaHSL(this.BaseColor).Lightness;

            // Set initial palette values
            // If there are colors darker than the base color
            if (Ramp.BaseColorIndex > 0)
            {
                // Sets the darkest color a fraction of the distance to the base color
                float step = GeneratedColorPalette.BASE_VALUE / (Ramp.BaseColorIndex + 1);
                SetValue(0, step);
            }
            else
            {
                Ramp.Generator.ShadowAmount = 0.5f;
            }

            // If there are colors lighter than the base color
            if (Ramp.BaseColorIndex < Ramp.Count - 1)
            {
                // Sets the lightest color a fraction of the distance to the base color
                float step = (1f - GeneratedColorPalette.BASE_VALUE) /
                             (Ramp.Count - Ramp.BaseColorIndex);
                SetValue(Ramp.Count - 1, 1f - step);
            }
            else
            {
                Ramp.Generator.Specularity = 0.5f;
            }

            var parameters = new PaletteParameters(this.BaseColor);

            // Minimize error on shadow amount
            MinimizeShadowError(parameters);
            // Minimize error on specularity
            MinimizeSpecularityError(parameters);
        }
예제 #16
0
        private List <Tuple <float, float> > Errors(
            PaletteGenerator generator,
            List <PaletteEntry> ramp,
            Range <float> range,
            int count,
            Func <PaletteParameters, float, float> function)
        {
            PaletteParameters copyParameters = (PaletteParameters)Clone();
            float             interval       = (range.Maximum - range.Minimum) / count;

            var errors = new List <Tuple <float, float> >();

            for (int i = 0; i <= count; i++)
            {
                float value = range.Minimum + interval * i;
                function(copyParameters, value);

                var   palette = generator.GetPalette(copyParameters);
                float error   = palette.GetError(ramp);
                errors.Add(Tuple.Create(value, error));
            }

            return(errors);
        }
예제 #17
0
 private PaletteParameters(PaletteParameters source)
 {
     CopyFrom(source);
 }
예제 #18
0
 public IndexedGeneratedPalette GetIndexedPalette(PaletteParameters parameters)
 {
     return(new IndexedGeneratedPalette(this, parameters));
 }
예제 #19
0
        public void MinimizeYellowError(PaletteParameters parameters)
        {
            var entries = Palette.RampEntries(Ramp);

            parameters.MinimizeYellowError(Ramp.Generator, entries);
        }
예제 #20
0
 public override void Read(BinaryReader input)
 {
     OtherNames.read(input);
     Parameters = PaletteParameters.ReadContent(input);
 }
예제 #21
0
 public RecolorEntry(PaletteParameters parameters)
 {
     OtherNames = new List <string>();
     Parameters = parameters;
 }
예제 #22
0
 public GeneratedColorPalette GetPalette(PaletteParameters parameters)
 {
     return(new GeneratedColorPalette(this, parameters));
 }